// BurnCDDlg.cpp : implementation file
//

#include "stdafx.h"
#include "BurnCD.h"
#include "BurnCDDlg.h"

#include "DiscMaster.h"
#include "FileObject.h"
#include "DirObject.h"
#include "DiscFormatData.h"
#include "DiscFormatRawCD.h"
#include "DiscRecorder.h"
#include "globals.h"
#include "madlldlib.h"
#include "MessageClassDlg.h"
#include "Wizard.h"
#include "mmsystem.h"
#include "scsidefs.h"
#include "ScsiCommand.h"
#include "afxdialogex.h"
#include "afxcmn.h"   ///progress control new stuff for vista +

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

UINT g_uTBBC = RegisterWindowMessage(_T("TaskbarButtonCreated"));
// CBurnCDDlg dialog
CBurnCDDlg::CBurnCDDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CBurnCDDlg::IDD, pParent)
, m_cancelBurn(false)
, m_cancelaudioBurn(false)
, m_cancelISOFromDisc(false)
, m_selectedMediaType(-1)
, m_addingdrives(false)
, m_nCurrentMode(PROGRAM_IDLE)
, m_cancelErase(false)
, m_bWaitingForDisc(FALSE)
, m_volumelabelchanged(FALSE)
,m_WizardMode(-1)

{
	m_volumeLabel = CTime::GetCurrentTime().Format(_T("%d_%b_%Y"));
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_BootImageFile = "";
	m_pTaskbarList = NULL;
	m_addfile =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_ADD_FILE), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_update =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_NET), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_delete =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_DELETE_SINGLE), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_deleteall =	(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_DELETE_ALL), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_eject =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_EJECT), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_save =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_SAVE), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_burn =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDR_MAINFRAME), IMAGE_ICON, 48,48, LR_DEFAULTCOLOR);
	m_stop =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_STOP), IMAGE_ICON, 48,48, LR_DEFAULTCOLOR);
	m_erase =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_CD), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_load =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_LOAD), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_up =			(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_UP), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_down =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_DOWN), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_help =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_INFO), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_wizard =		(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_WIZARD), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_isodisc	=	(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_DVD), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	m_saveibg	=	(HICON)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE( IDI_ICON_IBG), IMAGE_ICON, 24,24, LR_DEFAULTCOLOR);
	WizardDlg = NULL;

	m_TotalSectorsOnMedia = 0;
	m_RadioBurnFilesFolders = 0;
	m_mediaTypeEdit = _T("");
	m_oversizequestion = false;	
	m_mediaTypeEdit2 = _T("");
	m_ElapsedTime = 0;
	SpeedVector.clear();
	SectorVector.clear();
	RateVector.clear();
	BufferVector.clear();
	CPUVector.clear();	
	m_LayerBreak = 0;
	m_MediaCapacity = 0;
	m_datasectors = 0;
	m_BurnButtonClicked = 0;
}

void CBurnCDDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_DEVICE_COMBO, m_deviceComboBox);
	DDX_Control(pDX, IDC_BURN_FILE_LIST, m_fileListbox);
	DDX_Control(pDX, IDC_PROGRESS_TEXT, m_progressText);
	//  DDX_Control(pDX, IDC_ESTIMATED_TIME, m_estimatedTime);
	//  DDX_Control(pDX, IDC_TIME_LEFT, m_timeLeft);
	DDX_Control(pDX, IDC_PROGRESS, m_progressCtrl);
	DDX_Control(pDX, IDC_BUFFER_TEXT, m_bufferText);
	DDX_Control(pDX, IDC_BUFFER_PROG, m_bufferCtrl);
	DDX_Control(pDX, IDC_CAPACITY, m_capacityProgress);
	DDX_Control(pDX, IDC_MAX_TEXT, m_maxText);
	DDX_Text(pDX, IDC_VOLUME, m_volumeLabel);
	DDX_Control(pDX, IDC_TOTAL_TEXT, m_TotalSizeText);
	DDX_Radio(pDX, IDC_RADIOBURNFILES, m_RadioBurnFilesFolders);
	DDV_MinMaxInt(pDX, m_RadioBurnFilesFolders, 0, 1);
	DDX_Control(pDX, IDC_COMBO_UDF_REV, m_UDFRevision);
	DDX_Control(pDX, IDC_COMBO_MEDIA_SPEEDS, m_MediaSpeeds);
	DDX_Text(pDX, IDC_MEDIA_TYPE_EDIT, m_mediaTypeEdit);
	DDX_Control(pDX, IDC_COMBO_FILESYSTEM, m_FileSystemCombo);
	DDX_Control(pDX, IDC_CHECK_MULTISESSION, m_bMulti);
	DDX_Control(pDX, IDC_CHECK_BOOTIMAGE, m_CheckBootable);
	DDX_Control(pDX, IDC_CHECK_SHUTDOWNWHENCOMPLETE, m_CheckShutdown);
	DDX_Control(pDX, IDC_CHECK_BURNPROOF, m_BurnProof);
	DDX_Control(pDX, IDC_EJECT_WHEN_FINISHED, m_ejectWhenFinished);
	DDX_Control(pDX, IDC_CLOSE_MEDIA_CHK, m_closeMedia);
	DDX_Control(pDX, IDC_ADD_FILES_BUTTON, m_AddFile);
	DDX_Control(pDX, IDC_REMOVE_FILES_BUTTON, m_DeleteFile);
	DDX_Control(pDX, IDC_BUTTON_REMOVEALL, m_Delete_All);
	DDX_Control(pDX, IDC_BUTTON_EJECT, m_Eject);
	DDX_Control(pDX, IDC_BUTTON_SAVE, m_Save);
	DDX_Control(pDX, IDC_BURN_BUTTON, m_Burn);
	DDX_Control(pDX, IDC_ERASE, m_Erase);
	DDX_Control(pDX, IDC_BUTTON_LOAD, m_Load);
	DDX_Control(pDX, IDC_STATICLISTWINDOW, m_StaticListWindow);
	DDX_Control(pDX, IDC_BUTTON_DOWN, m_Down);
	DDX_Control(pDX, IDC_BUTTON_UP, m_Up);
	DDX_Control(pDX, IDC_HELPBUTTON, m_Help);
	DDX_Control(pDX, IDC_COMBO_VERIFY, m_VerifyCombo);
	DDX_Control(pDX, IDC_PROGRESS_TRACK, m_ProgressTrack);
	DDX_Control(pDX, IDC_TRACK_PROGRESS_TEXT, m_progressTrackText);
	DDX_Control(pDX, IDC_UPDATE_BUTTON, m_Update);
	DDX_Control(pDX, IDC_BUTTON_WIZARD, m_Wizard);
	DDX_Control(pDX, IDC_ISODISC, m_Isodisc);
	DDX_Control(pDX, IDC_EDIT_NUMCOPIES, m_NumberofCopies);
	DDX_Control(pDX, IDC_SPIN2, m_SpinNCopies);
	//  DDX_Control(pDX, IDC_COMBO_ROTATION, m_Rotation);
	DDX_Control(pDX, IDC_CHECK_USECAV, m_CheckUseCAV);
	DDX_Text(pDX, IDC_MEDIA_TYPE_EDIT2, m_mediaTypeEdit2);
	DDX_Control(pDX, IDC_BUTTON_SAVEIBG, m_SaveIBG);
}

/*//}}AFX_MSG_MAP//{{AFX_MSG_MAP(CBurnCDDlg)*/
BEGIN_MESSAGE_MAP(CBurnCDDlg, CDialogEx)

	ON_BN_CLICKED(IDC_CHECK_BOOTIMAGE, &CBurnCDDlg::OnClickedCheckBootimage)
	ON_BN_CLICKED(IDC_BUTTON_SAVE, &CBurnCDDlg::OnClickedButtonSave)
	ON_BN_CLICKED(IDC_BUTTON_LOAD, &CBurnCDDlg::OnClickedButtonLoad)
	ON_BN_CLICKED(IDC_BUTTON_UP, &CBurnCDDlg::OnFolderUp)
	ON_BN_CLICKED(IDC_BUTTON_DOWN, &CBurnCDDlg::OnFolderdown)
	ON_BN_CLICKED(IDC_HELPBUTTON, &CBurnCDDlg::OnClickedHelpbutton)
	ON_BN_CLICKED(IDC_ADD_FILES_BUTTON, &CBurnCDDlg::OnBnClickedAddFilesButton)
	ON_BN_CLICKED(IDC_BURN_BUTTON, &CBurnCDDlg::OnBnClickedBurnButton)
	ON_BN_CLICKED(IDC_REMOVE_FILES_BUTTON, &CBurnCDDlg::OnBnClickedRemoveFilesButton)
	ON_BN_CLICKED(IDC_RADIOBURNFILES, &CBurnCDDlg::OnClickedRadioburnfiles)
	ON_BN_CLICKED(IDC_ERASE, &CBurnCDDlg::OnClickedErase)
	ON_BN_CLICKED(IDC_BUTTON_EJECT, &CBurnCDDlg::OnClickedButtonEject)
	ON_BN_CLICKED(IDC_CHECK_BURNPROOF, &CBurnCDDlg::OnClickedCheckBurnproof)
	ON_BN_CLICKED(IDC_EJECT_WHEN_FINISHED, &CBurnCDDlg::OnClickedEjectWhenFinished)
	ON_BN_CLICKED(IDC_BUTTON_REMOVEALL, &CBurnCDDlg::OnClickedButtonRemoveall)
	ON_BN_CLICKED(IDC_CLOSE_MEDIA_CHK, &CBurnCDDlg::OnClickedCloseMediaChk)
	ON_BN_CLICKED(IDC_CHECK_MULTISESSION, &CBurnCDDlg::OnClickedCheckMultisession)
	ON_BN_CLICKED(IDC_CHECK_SHUTDOWNWHENCOMPLETE, &CBurnCDDlg::OnClickedCheckShutdownwhencomplete)
	ON_CBN_SELCHANGE(IDC_COMBO_UDF_REV, &CBurnCDDlg::OnSelchangeComboUdfRev)
	ON_CBN_SELCHANGE(IDC_COMBO_MEDIA_SPEEDS, &CBurnCDDlg::OnSelchangeComboMediaSpeeds)
	ON_CBN_SELCHANGE(IDC_COMBO_FILESYSTEM, &CBurnCDDlg::OnSelchangeComboFilesystem)
	ON_CBN_SELCHANGE(IDC_COMBO_VERIFY, &CBurnCDDlg::OnSelchangeComboVerify)
	ON_CBN_SELCHANGE(IDC_DEVICE_COMBO, &CBurnCDDlg::OnCbnSelchangeDeviceCombo)
	ON_LBN_SELCHANGE(IDC_BURN_FILE_LIST, &CBurnCDDlg::OnLbnSelchangeBurnFileList)
	ON_MESSAGE(WM_IMAPI_UPDATE, OnImapiUpdate)
	ON_MESSAGE(WM_IMAPI_AUDIO_UPDATE, OnImapiAudioUpdate)
	ON_MESSAGE(WM_IMAPI_RAW_UPDATE, OnImapiRawUpdate)
	ON_MESSAGE(WM_IMAPI_FS_UPDATE, OnImapiFsUpdate)
	ON_MESSAGE(WM_BURN_STATUS_MESSAGE, OnBurnStatusMessage)
	ON_MESSAGE(WM_BURN_FINISHED, OnBurnFinished)
	ON_MESSAGE(WM_ERASE_FINISHED, OnEraseFinished)
	ON_MESSAGE (WM_UPDATEDATA, OnUpdateData)
	ON_COMMAND(IDC_RADIOBURNISO, &CBurnCDDlg::OnRadioburniso)
	ON_WM_DESTROY()
	ON_WM_DROPFILES()
	ON_WM_CLOSE()
	ON_WM_SYSCOMMAND()
	ON_BN_CLICKED(IDC_UPDATE_BUTTON, &CBurnCDDlg::OnClickedUpdateButton)
	ON_BN_CLICKED(IDC_BUTTON_WIZARD, &CBurnCDDlg::OnClickedButtonWizard)
	ON_WM_TIMER()
	ON_COMMAND(ID_TOOLS_SETTINGS, &CBurnCDDlg::OnMenuToolsSettings)
	ON_COMMAND(ID_HELP_DVDINFOPROBURNERONTHEWEB, &CBurnCDDlg::OnHelpDvdinfoproburnerontheweb)
	ON_COMMAND(ID_HELP_ABOUTDVDINFOPROBURNER, &CBurnCDDlg::OnHelpAboutdvdinfoproburner)
	ON_BN_CLICKED(IDC_ISODISC, &CBurnCDDlg::OnClickedIsodisc)
	ON_EN_CHANGE(IDC_EDIT_NUMCOPIES, &CBurnCDDlg::OnChangeEditCopies)
	ON_WM_VSCROLL()
	ON_MESSAGE(WM_SYSTEMTRAY, OnSystemTray)
	ON_MESSAGE(WM_TRAY, OnTray)
	ON_REGISTERED_MESSAGE( g_uTBBC, CBurnCDDlg::OnCreateThumbToolBar )
	ON_BN_CLICKED(IDC_CHECK_USECAV, &CBurnCDDlg::OnClickedCheckUsecav)
	ON_BN_CLICKED(IDC_BUTTON_SAVEIBG, &CBurnCDDlg::OnClickedButtonSaveibg)
	ON_EN_CHANGE(IDC_VOLUME, &CBurnCDDlg::OnChangeVolume)
END_MESSAGE_MAP()

LRESULT CBurnCDDlg::OnCreateThumbToolBar (WPARAM wParam, LPARAM lParam )
{
	DWORD dwMajor = LOBYTE(LOWORD(GetVersion()));
	DWORD dwMinor = HIBYTE(LOWORD(GetVersion()));
	HRESULT hr;
	// Check that the OS is Win 7 or later (Win 7 is v6.1).
	if ( dwMajor > 6 || ( dwMajor == 6 && dwMinor > 0 ) )
	{
		// Remember to release after use
		if( NULL == m_pTaskbarList )
		{
			hr = CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_ALL,  IID_ITaskbarList3, (void**)&m_pTaskbarList);
			if (SUCCEEDED(hr))
			{
				m_pTaskbarList->HrInit();
			}
		}
	}
  return 0;
}

//this sets the install folder in the registry to DVDInfoPro can find it
BOOL CBurnCDDlg::SetInstallDirectory()
{
	char  drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT], sProgramPath[MAX_PATH];
	_splitpath_s((char *)AfxGetApp()->m_pszHelpFilePath, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT );
	_makepath_s(sProgramPath, MAX_PATH,  drive, dir, NULL, NULL);
	WriteString("InstallDirectory", sProgramPath);
	return TRUE;
}

// CBurnCDDlg message handlers
BOOL CBurnCDDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
#ifdef _BETA
	//Beta Expiry
	COleDateTime time = COleDateTime::GetCurrentTime();
	if (time.GetYear() >= EXPIREYEAR && time.GetMonth() >= EXPIREMONTH && time.GetDay() >= EXPIREDAY)
	{
		MessageBox("This beta has expired, please contact Nic for a newer beta build");
		exit(0);
	}
#endif
	SetInstallDirectory();
	::CoInitializeEx(NULL, COINIT_MULTITHREADED);//
	SetBackgroundColor();
	pThis = this;
	InitToolTips();
	// Add "About..." menu item to system menu.
	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	CMenu menu;
	menu.LoadMenuA(IDR_MENU1);
	SetMenu(&menu);
	DragAcceptFiles(TRUE);
	SetControlDefaults();
	SetIcons();
	GetDisplayColors();
	AddSystemTrayIcon();
	SetFonts();
	SetTimer(STARTUP_TIMER, 10, NULL);
	UpdateData(FALSE);
	return TRUE;  // return TRUE  unless you set the focus to a control
}

//Set various variables and controls defaults
void CBurnCDDlg::SetControlDefaults()
{
	m_MediaSpeeds.ResetContent();
	m_MediaSpeeds.AddString("Auto");
	m_progressText.SetWindowText(_T("Progress:"));
	m_progressTrackText.SetWindowText("Track Progress:");
	m_bufferText.SetWindowText(_T("Buffer Empty"));
	m_maxText.SetWindowText(_T("0"));
	m_capacityProgress.SetRange(0,100);

	m_nAutoFileSystem = -1;
	m_AutoUDFVersion = -1;
	m_TotalSizeText.SetWindowText("0");
	m_FileSystemCombo.SetCurSel(FS_AUTO);
	GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
	GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
	m_VerifyCombo.SetCurSel(0);
	m_CheckUseCAV.SetCheck(0);
	m_ejectWhenFinished.SetCheck(GetInt("EjectWhenFinished", 1));
	m_NumberofCopies.SetWindowTextA("1");
	m_SpinNCopies.SetRange(1, 99);
	m_SpinNCopies.SetPos(1);
	m_closeMedia.SetCheck(FALSE);
}

//set the UI icons as loaded in the constructor
void CBurnCDDlg::SetIcons()
{
	m_AddFile.SetIcon(m_addfile); 
	m_Update.SetIcon(m_update); 
	m_DeleteFile.SetIcon(m_delete); 
	m_Delete_All.SetIcon(m_deleteall); 
	m_Eject.SetIcon(m_eject); 
	m_Burn.SetIcon(m_burn); 
	m_Save.SetIcon(m_save); 
	m_Erase.SetIcon(m_erase); 
	m_Load.SetIcon(m_load); 
	m_Up.SetIcon(m_up); 
	m_Down.SetIcon(m_down); 
	m_Help.SetIcon(m_help); 
	m_Wizard.SetIcon(m_wizard); 
	m_Isodisc.SetIcon(m_isodisc); 
	m_SaveIBG.SetIcon(m_saveibg);
}

//set the fonts for everything so users font settings dont
//bugger up all our ui
void CBurnCDDlg::SetFonts()
{
	LOGFONT lf;  
	// Redraw of child controls is not needed in OnInitDialog since controls 
	// are not drawn yet.
	short int fRedraw= FALSE; 
	memset(&lf, 0, sizeof(LOGFONT));  // Clear out structure.
	lf.lfHeight = 14;                 // Request a 15-pixel-high font
	strcpy_s(lf.lfFaceName, 32, "Microsoft Sans Serif");   // with face name "Arial".
	mFont.CreateFontIndirect(&lf);   // Create the font. 
	SendMessageToDescendants(WM_SETFONT, (WPARAM)mFont.m_hObject,  // Handle to font
							 MAKELONG ((WORD) fRedraw, 0), TRUE);  // Send to all descendants(TRUE) or just children of *this (FALSE)
	GetDlgItem(IDC_ADD_FILES_BUTTON)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_UPDATE_BUTTON)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_REMOVE_FILES_BUTTON)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_REMOVEALL)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_DEVICE_COMBO)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BURN_FILE_LIST)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_VOLUME)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_CLOSE_MEDIA_CHK)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_RADIOBURNFILES)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_RADIOBURNISO)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BURN_BUTTON)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_ERASE)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_EJECT)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_COMBO_UDF_REV)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_COMBO_MEDIA_SPEEDS)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_CHECK_BURNPROOF)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_COMBO_FILESYSTEM)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_EJECT_WHEN_FINISHED)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_CHECK_MULTISESSION)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_CHECK_BOOTIMAGE)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_SAVE)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_LOAD)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_UP)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_DOWN)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_BUTTON_WIZARD)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_ISODISC)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_EDIT_NUMCOPIES)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_SPIN2)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATICVOLUME)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATICUDFREV)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATICFILESYSTEM)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATICSPEED)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATIC_VERIFY)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATICLISTWINDOW)->SetFont	(&mFont, TRUE);
	GetDlgItem(IDC_STATIC_NUMCOPIES)->SetFont	(&mFont, TRUE);
	mFont.Detach();
	CClientDC dc(this);
	VERIFY(mFont.CreatePointFont(80, "Courier", &dc));
	mFont.Detach();
}

//This is done via  message then it can be sent via a thread
//which cannot call UpdateData()
LRESULT CBurnCDDlg::OnUpdateData (WPARAM, LPARAM)
{
	UpdateData(FALSE);
	return 0;
}

//intialize control tooltips
void CBurnCDDlg::InitToolTips()
{
	SAFE_LOG(out, "InitToolTips() Start", true);
	if(!m_pToolTip.Create(this, TTS_ALWAYSTIP))
	{
		TRACE(_T("Unable To create ToolTip\n"));
		return;
	}
	ADDTOOL(IDC_ADD_FILES_BUTTON),		_T("Add Multiple File(s) && Folder(s) - Browse for multiple files and folders to add to the burn list (Drag && drop is supported)"));
	ADDTOOL(IDC_UPDATE_BUTTON),			_T("Check the website for the latest version of the program"));
	ADDTOOL(IDC_REMOVE_FILES_BUTTON),	_T("Remove single item - Removes the selected item from the list"));
	ADDTOOL(IDC_BUTTON_REMOVEALL),		_T("Remove All - Removes all items from the list"));
	ADDTOOL(IDC_DEVICE_COMBO),			_T("List of supported CD/DVD/Bluray drives on the computer"));
	ADDTOOL(IDC_BURN_FILE_LIST),		_T("List of files && folder to burn to the disc, or a single ISO file to burn as an image"));
	ADDTOOL(IDC_VOLUME),				_T("The Volume label to name the disc.  One multisession you can change this to rename the disc"));
	ADDTOOL(IDC_CLOSE_MEDIA_CHK),		_T("Closes the disc when burning is complete.  Some drives may not read discs that are not closed"));
	ADDTOOL(IDC_RADIOBURNFILES),		_T("Burns the files && folders list to the disc"));
	ADDTOOL(IDC_RADIOBURNISO),			_T("Burns an ISO file to the disc as an image.  The ISO file must be the only file in the list box"));
	ADDTOOL(IDC_BURN_BUTTON),			_T("Starts the burning or ISO write process"));
	ADDTOOL(IDC_ERASE),					_T("Erase the re-writable disc in the current drive"));
	ADDTOOL(IDC_BUTTON_EJECT),			_T("Eject the disc in the current drive"));
	ADDTOOL(IDC_COMBO_UDF_REV),			_T("Supported UDF versions (Universal Disc Format)"));
	ADDTOOL(IDC_COMBO_MEDIA_SPEEDS),	_T("Supported speeds for drive/media combination"));
	ADDTOOL(IDC_CHECK_BURNPROOF),		_T("Enables or disables buffer underrun protection"));
	ADDTOOL(IDC_COMBO_FILESYSTEM),		_T("List of supported file systems to choose from"));
	ADDTOOL(IDC_EJECT_WHEN_FINISHED),	_T("Eject the disc when burn or erase operations are complete"));
	ADDTOOL(IDC_CHECK_MULTISESSION),	_T("Add the files in the list to the data already on the disc"));
	ADDTOOL(IDC_CHECK_BOOTIMAGE),		_T("Bootable disc. Load a boot image file. Automatic support of 1.20MB, 1.44MB or 2.88MB boot images"));
	ADDTOOL(IDC_BUTTON_SAVE),			_T("Save the list to a file (*.dpb *.ibb)"));
	ADDTOOL(IDC_BUTTON_LOAD),			_T("Load the list from a file (*.dpb *.ibb)"));
	ADDTOOL(IDC_BUTTON_UP),				_T("Moves the selected item in the list up"));
	ADDTOOL(IDC_BUTTON_DOWN),			_T("Moves the selected item in the list down"));
	ADDTOOL(IDC_HELPBUTTON),			_T("Opens the help document"));
	ADDTOOL(IDC_COMBO_VERIFY),			_T("Verifies the type of verification after disc is burned"));
	ADDTOOL(IDC_BUTTON_WIZARD),			_T("A wizard that sets the program defaults for the type of disc you want to burn"));
	ADDTOOL(IDC_ISODISC),				_T("Creates an ISO image from the disc in the currently selected drive"));
	ADDTOOL(IDC_EDIT_NUMCOPIES),		_T("Number of copies to burn"));
	ADDTOOL(IDC_SPIN2),					_T("increment or decrement the number of copies by 1"));
	ADDTOOL(IDC_CHECK_USECAV),		    _T("Use 'Constant Angular Velocity' if supported otherwise 'Constant Linear Velocity'"));
	ADDTOOL(IDC_BUTTON_SAVEIBG),		_T("Saves the burning data to a file to display in DVDInfoPro as a graph"));
	
	m_pToolTip.Activate(TRUE);	
	m_pToolTip.SetTipBkColor(RGB(255,255,0));
	SAFE_LOG(out, _T("InitToolTips() End"), true);	
}

//parses all drives on the system and adds them to the combobox then a Hard Disk
UINT CBurnCDDlg::AddRecordersToComboBoxThread(LPVOID pParam)
{
	pThis->m_addingdrives = true;
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Initializing Please Wait...");
	bool firsttime = true;
	CDiscMaster			discMaster;
	// Cleanup old data on combobox
	int itemCount = pThis->m_deviceComboBox.GetCount();
	if (itemCount)
		firsttime = false;
	for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
	{
		delete (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(itemIndex);
	}
	pThis->m_deviceComboBox.ResetContent();
	if (!discMaster.Initialize())
	{
		AfxMessageBox(discMaster.GetErrorMessage(), MB_OK|MB_ICONERROR);
		pThis->EndDialog(IDOK);
		pThis->m_addingdrives = false;
		return 0;
	}
	// Add Devices to ComboBox
	long totalDevices = discMaster.GetTotalDevices();
	if (totalDevices == 0 && FAILED(discMaster.GetHresult()))
	{
		AfxMessageBox(discMaster.GetErrorMessage(), MB_OK|MB_ICONERROR);
	}
	for (long deviceIndex = 0; deviceIndex < totalDevices; deviceIndex++)
	{
		CString str;
		str.Format("Initializing Device %d of %d", deviceIndex, totalDevices);
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str.GetBuffer(0));
		if (pThis->WizardDlg)
			pThis->WizardDlg->scanDlg->SetText(&str);
		CString recorderUniqueID = discMaster.GetDeviceUniqueID(deviceIndex);
		if (recorderUniqueID.IsEmpty())
		{
			CString errorMessage(discMaster.GetErrorMessage());
			if (!errorMessage.IsEmpty())
			{
				AfxMessageBox(errorMessage, MB_OK|MB_ICONERROR);
				continue;
			}
		}
		// Create an IDiscRecorder2
		CDiscRecorder* pDiscRecorder = new CDiscRecorder();
		ASSERT(pDiscRecorder != NULL);
		if (pDiscRecorder == NULL)
			continue;
		if (!pDiscRecorder->Initialize(recorderUniqueID))
		{
			if (totalDevices == 1 && FAILED(pDiscRecorder->GetHresult()))
			{
				CString errorMessage;
				errorMessage.Format(_T("Failed to prepare burner - Error:0x%08x\n\nBurner Unique ID:%s"),
					pDiscRecorder->GetHresult(), (LPCTSTR)recorderUniqueID);
				AfxMessageBox(errorMessage, MB_OK|MB_ICONERROR);
			}
			delete pDiscRecorder;
			continue;
		}
		// Get the volume path(s). usually just 1
		CString volumeList;
		ULONG totalVolumePaths = pDiscRecorder->GetTotalVolumePaths();
		for (ULONG volIndex = 0; volIndex < totalVolumePaths; volIndex++)
		{
			if (volIndex)
				volumeList += _T(",");
			volumeList += pDiscRecorder->GetVolumePath(volIndex);
		}
		// Add Drive to combo and IDiscRecorder as data
		int legacy = pDiscRecorder->GetLegacyDeviceNumber();
		CString vendorId = pDiscRecorder->GetVendorId();
		CString productId = pDiscRecorder->GetProductID();
		CString productrev = pDiscRecorder->GetProductRevision();
		CString strName;
		strName.Format(_T("%d (%s:) %s %s (%s)"), legacy, (LPCTSTR)volumeList, (LPCTSTR)vendorId, (LPCTSTR)productId, (LPCTSTR)productrev);
		int comboBoxIndex = pThis->m_deviceComboBox.AddString(strName);
		pThis->m_deviceComboBox.SetItemDataPtr(comboBoxIndex, pDiscRecorder);
	}
	pThis->m_deviceComboBox.AddString("Hard Disk (Make ISO image from files & folders)");
	if (totalDevices > 0)
	{
		//m_deviceComboBox.SetCurSel(0);
		//pThis->MessageBox(pThis->m_argv);
		if (pThis->m_argc > 1)
		{
			//pThis->MessageBox(pThis->m_argv);
			CString str = pThis->m_argv.Left(2);
			pThis->SelectDriveFromArgument(&str);
		}
		else
			pThis->SetLastSelectedDrive();
		pThis->ChangeDeviceCombo();
	}
	
	pThis->m_addingdrives = false;
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Initialization Complete...");
	if (pThis->WizardDlg)
	{
		pThis->WizardDlg->scanDlg->SetText("Initialization Complete...");
		pThis->WizardDlg->EnableWizardOK = TRUE;
	}
	if (firsttime)
		pThis->PlayStartupSound();
	return 0;
}

// Selected a New Device
void CBurnCDDlg::OnCbnSelchangeDeviceCombo()
{
	if (m_deviceComboBox.GetCurSel() == m_deviceComboBox.GetCount()-1) //Hard disk selected
	{
		GetDlgItem(IDC_BURN_BUTTON)->EnableWindow(m_fileListbox.GetCount()>0);
		return;
	}
	ChangeDeviceCombo();
}

CString CBurnCDDlg::GetDiscStateString(IMAPI_FORMAT2_DATA_MEDIA_STATE state)
{
	CString statestr;
	switch (state)
	{
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_UNKNOWN:
			statestr = "State unknown";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_INFORMATIONAL_MASK:
			statestr = "Informational Mask";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_UNSUPPORTED_MASK:
			statestr = "UnSupported Mask";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_OVERWRITE_ONLY: // or IMAPI_FORMAT2_DATA_MEDIA_STATE_RANDOMLY_WRITABLE:  // same value
			statestr = "Overwrite/Random Write";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK:
			statestr = "Media Blank";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_APPENDABLE:
			statestr = "Multisession";	
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_FINAL_SESSION:
			statestr = "Final Session";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_DAMAGED:
			statestr = "Damaged, Try Erase";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_ERASE_REQUIRED:
			statestr = "Erase Required";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_NON_EMPTY_SESSION:
			statestr = "Non Empty Session";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_WRITE_PROTECTED:
			statestr = "Not Writeable";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_FINALIZED:
			statestr = "Disc Closed";
		break;
		case IMAPI_FORMAT2_DATA_MEDIA_STATE_UNSUPPORTED_MEDIA:
			statestr = "Unsupported Disc";
		break;
	}
	return statestr;
}

void CBurnCDDlg::ChangeDeviceCombo()
{

	//m_volumeLabel = CTime::GetCurrentTime().Format(_T("%d_%b_%Y"));
	m_CurrentMediaBurning= IMAPI_MEDIA_TYPE_UNKNOWN;
	m_start = false;
	m_isCdromSupported = false;
	m_isDvdSupported = false;
	m_isDualLayerDvdSupported = false;
	m_isBDSupported = false;
	m_isHDDVDSupported = false;
	GetDlgItem(IDC_ERASE)->EnableWindow(FALSE);
	int prev = m_MediaSpeeds.GetCurSel();
	if (prev < 0)
		prev = 0;
	m_MediaSpeeds.ResetContent();
	m_MediaSpeeds.AddString("Auto");
	//m_MediaSpeeds.EnableWindow(FALSE);
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return;
	}
	double freesectors = 0;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		IMAPI_MEDIA_PHYSICAL_TYPE value;
		HRESULT hRes = pIDiscFormatData->get_CurrentPhysicalMediaType(&value);
		CString media;
		if (hRes == S_OK)
		{
			 media = GetMediaTypeString((int)value);
			 pIDiscFormatData->get_TotalSectorsOnMedia(&m_TotalSectorsOnMedia);
			 //m_MediaCapacity = m_TotalSectorsOnMedia;
			 FillSpeedsComboBox();
			 freesectors = GetFreeSectors();
			 
		} 
		else if (value == IMAPI_MEDIA_TYPE_UNKNOWN)
		{
			media = "No Media Loaded";
		}
		// Display Supported Media Types
		CString supportedMediaTypes;
		ULONG totalMediaTypes = discFormatData.GetTotalSupportedMediaTypes();
		for (ULONG volIndex = 0; volIndex < totalMediaTypes; volIndex++)
		{
			int mediaType = discFormatData.GetSupportedMediaType(volIndex);
			if (volIndex > 0)
				supportedMediaTypes += _T(", ");
			supportedMediaTypes += GetMediaTypeString(mediaType);
		}
		m_mediaTypeEdit = "No Disc Loaded";
		m_mediaTypeEdit2 = "";
		switch((int)value) //Set erase button enabled for all re-writable media
		{
			case IMAPI_MEDIA_TYPE_CDRW:
			case IMAPI_MEDIA_TYPE_DVDRAM:
			case IMAPI_MEDIA_TYPE_DVDPLUSRW:
			case IMAPI_MEDIA_TYPE_BDRE:
			case IMAPI_MEDIA_TYPE_DVDDASHRW:
			case IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
			case IMAPI_MEDIA_TYPE_HDDVDRAM:
				GetDlgItem(IDC_ERASE)->EnableWindow(TRUE);
			break;
		}
		if (hRes == S_OK)
		{
			int blank = isMediaBlank();
			CString statestr;
			if (blank)
				statestr = "(Disc Blank)";
			else
			{
				IMAPI_FORMAT2_DATA_MEDIA_STATE state;
				HRESULT hr = GetMediaState(&state);
				if (SUCCEEDED(hr)) 
				{
				 statestr = GetDiscStateString(state);
				}
				else
					statestr = "";
			}
			double size;
			//FillSpeedsComboBox();//***
			CString MaxSpeed;
			m_MediaSpeeds.GetLBText(1, MaxSpeed);
			m_midcode = "";
			GetMediaMidCode(&m_midcode);

			switch ((int)value)
			{
				case IMAPI_MEDIA_TYPE_CDROM:
				case IMAPI_MEDIA_TYPE_CDR:
				case IMAPI_MEDIA_TYPE_CDRW:
					m_selectedMediaType = CD_MEDIA;
					size = (freesectors*2048)/1048576;
					m_mediaTypeEdit.Format(_T("%s 700MB CD - (%s)"), media, MaxSpeed);
					m_mediaTypeEdit2.Format(_T("%4.2fMB free %s"), size, statestr);
					
					m_nAutoFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet;
					m_AutoUDFVersion = 0x102;
				break;
				case IMAPI_MEDIA_TYPE_DVDROM:
				case IMAPI_MEDIA_TYPE_DVDRAM:
				case IMAPI_MEDIA_TYPE_DVDPLUSR:
				case IMAPI_MEDIA_TYPE_DVDPLUSRW:	
				case IMAPI_MEDIA_TYPE_DVDDASHR:
				case IMAPI_MEDIA_TYPE_DVDDASHRW:
					m_selectedMediaType = DVD_MEDIA;
					size = freesectors/524288;
					m_mediaTypeEdit.Format(_T("%s 4.7GB SL - (%s) (%s)"), media, MaxSpeed, m_midcode);
					m_mediaTypeEdit2.Format(_T("%4.2fGB free %s"), size, statestr);
					m_nAutoFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet;
					m_AutoUDFVersion = 0x102;
				break;
				case IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:
				case IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
				case IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
					m_selectedMediaType = DL_DVD_MEDIA;
					size = freesectors/524288;
					m_mediaTypeEdit.Format(_T("%s 8.5GB DL - (%s) (%s)"), media, MaxSpeed, m_midcode);
					m_mediaTypeEdit2.Format(_T("%4.2fGB free %s"), size, statestr);
					m_nAutoFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet;
					m_AutoUDFVersion = 0x102;
				break;
				case IMAPI_MEDIA_TYPE_BDROM:
				case IMAPI_MEDIA_TYPE_BDR:
				case IMAPI_MEDIA_TYPE_BDRE:
					size = freesectors/524288;
					if (m_TotalSectorsOnMedia/524288 < 25)
					{
						m_selectedMediaType = BD_MEDIA;
						m_mediaTypeEdit.Format(_T("%s 25GB Blu-ray - (%s) (%s)"), media, MaxSpeed, m_midcode);
						m_mediaTypeEdit2.Format(_T("%4.2fGB free %s"), size, statestr);
					
					}
					else
					{
						m_selectedMediaType = DL_BD_MEDIA;						
						m_mediaTypeEdit.Format(_T("%s 50GB DL Blu-ray - (%s) (%s)"), media, MaxSpeed, m_midcode);
						m_mediaTypeEdit2.Format(_T("%4.2fGB free %s"), size, statestr);
					
					}
					m_nAutoFileSystem = FsiFileSystemUDF;
					m_AutoUDFVersion = 0x250;
				break;	
				case IMAPI_MEDIA_TYPE_HDDVDROM:
				case IMAPI_MEDIA_TYPE_HDDVDR:
				case IMAPI_MEDIA_TYPE_HDDVDRAM:
					m_selectedMediaType = HDDVD_MEDIA;
					size = freesectors/524288;
					if (m_TotalSectorsOnMedia/524288 < 16)
					{
						m_mediaTypeEdit.Format(_T("%s 15GB HD-DVD (%s) (%s)"), media, MaxSpeed, m_midcode);
						m_mediaTypeEdit2.Format(_T("%4.2fGB free %s"), size, statestr);
					}
					else
					{
						m_mediaTypeEdit.Format(_T("%s 30GB HD-DVD (%s) (%s)"), media, MaxSpeed, m_midcode);
						m_mediaTypeEdit2.Format(_T("%4.2fGB free %s"), size, statestr);
					}
					m_nAutoFileSystem = FsiFileSystemUDF;
					m_AutoUDFVersion = 0x250;
				break;
				default:
					m_selectedMediaType = UNKNOWN_MEDIA;
					size = freesectors/524288;
					m_mediaTypeEdit.Format(_T("%s Media Unknown"), media);
					m_mediaTypeEdit2 = _T("");

					m_nAutoFileSystem = FsiFileSystemUDF;
					m_AutoUDFVersion = 0x102;
				break;
			}
			m_CurrentMediaBurning = value;  //used during burn for update progress
			UpdateCapacity();
			GetVolumeName();
		}
	}
	//Get the SAFEARRAY from the supported UDF Revisions
	//Then extract each element which is a Variant
	//The type we want is in iVal and are VT_I4 type
	//We then set which  UDF revs are available
	b102 = b150 = b200 = b201 = b250 = b260 = FALSE;
	SAFEARRAY *pVal = GetSupportedUDFRevisions();
	if (pVal)
	{
		long nIRTypes = pVal->rgsabound->cElements;
		for( LONG irType = 0; irType < nIRTypes; ++irType )
		{
			VARIANT v;
			SafeArrayGetElement(pVal, &irType, &v);
			switch (v.iVal)
			{
				case 0x102:
					b102 = TRUE; 
				break;
				case 0x150:
					b150 = TRUE; 
				break;
				case 0x200:
					b200 = TRUE; 
				break;
				case 0x201:
					b201 = TRUE; 
				break;
				case 0x250:
					b250 = TRUE; 
				break;
				case 0x260:
					b260 = TRUE; 
				break;
			}		
		}
	}
	m_MediaSpeeds.SetCurSel(prev);
	FillUDFRevisionsCombo();
	SafeArrayUnaccessData(pVal);	
	m_BurnProof.SetCheck(GetBufferUnderrunEnabled());
	this->SendMessage(WM_UPDATEDATA, 0, 0); //we are doing it this way outside of a thread as a thread calls this function.
	EnableBurnButton();
	//EnableUI(TRUE);
}	

CString	CBurnCDDlg::GetMediaTypeString(int mediaType)
{

	switch (mediaType)
	{
	case IMAPI_MEDIA_TYPE_UNKNOWN:
	default:
		return _T("Unknown Media Type");

	case IMAPI_MEDIA_TYPE_CDROM:
		m_isCdromSupported = true;
		return _T("CD-ROM or CD-R/RW media");

	case IMAPI_MEDIA_TYPE_CDR:
		m_isCdromSupported = true;
		return _T("CD-R");

	case IMAPI_MEDIA_TYPE_CDRW:
		m_isCdromSupported = true;
		return _T("CD-RW");

	case IMAPI_MEDIA_TYPE_DVDROM:
		m_isDvdSupported = true;
		return _T("DVD ROM");

	case IMAPI_MEDIA_TYPE_DVDRAM:
		m_isDvdSupported = true;
		return _T("DVD-RAM");

	case IMAPI_MEDIA_TYPE_DVDPLUSR:
		m_isDvdSupported = true;
		return _T("DVD+R");

	case IMAPI_MEDIA_TYPE_DVDPLUSRW:
		m_isDvdSupported = true;
		return _T("DVD+RW");

	case IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:

		m_isDualLayerDvdSupported = true;
		return _T("DVD+R Dual Layer");
	
	case IMAPI_MEDIA_TYPE_DVDDASHR:
		m_isDvdSupported = true;
		return _T("DVD-R");

	case IMAPI_MEDIA_TYPE_DVDDASHRW:
		m_isDvdSupported = true;
		return _T("DVD-RW");

	case IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
		m_isDualLayerDvdSupported = true;
		return _T("DVD-R Dual Layer");

	case IMAPI_MEDIA_TYPE_DISK:
		return _T("random-access writes");

	case IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
		m_isDualLayerDvdSupported = true;
		return _T("DVD+RW DL");

	case IMAPI_MEDIA_TYPE_HDDVDROM:
		return _T("HD DVD-ROM");

	case IMAPI_MEDIA_TYPE_HDDVDR:
		return _T("HD DVD-R");

	case IMAPI_MEDIA_TYPE_HDDVDRAM:
		return _T("HD DVD-RAM");

	case IMAPI_MEDIA_TYPE_BDROM:
		return _T("BD-ROM");
	
	case IMAPI_MEDIA_TYPE_BDR:
		m_isBDSupported = true;
		return _T("BD-R");

	case IMAPI_MEDIA_TYPE_BDRE:
		m_isBDSupported = true;
		return _T("BD-RE");
	}
}

void CBurnCDDlg::OnLbnSelchangeBurnFileList()
{
	GetDlgItem(IDC_REMOVE_FILES_BUTTON)->EnableWindow(m_fileListbox.GetCurSel()!=-1);
	m_oversizequestion = false;
}

void CBurnCDDlg::OnFolderUp() 
{
	CString tmpname;
	if (m_fileListbox.GetCount() <= 1)
		return;
	int index = m_fileListbox.GetCurSel();
	if (index == -1)
	{
		MessageBox(_T("You must first select an entry"));
		return;
	}
	else if (index > 0)
	{
		CBaseObject* obj = (CBaseObject*)m_fileListbox.GetItemDataPtr(index);
		m_fileListbox.GetText(index, tmpname);
		m_fileListbox.SetItemDataPtr(index, 0);
		m_fileListbox.DeleteString(index);
		m_fileListbox.SetCurSel(m_fileListbox.InsertString(index-1, tmpname));
		m_fileListbox.SetItemDataPtr(index-1, obj);
		m_fileListbox.SetSel(index-1, 1);// reselect the item as moving it un-selects it
	}	
	else if (index == 0)
		MessageBox(_T("You cannot move the first entry up"));
}

void CBurnCDDlg::OnFolderdown() 
{
	CString tmpname;
	int count = m_fileListbox.GetCount();
	if (count <= 1)
		return;
	int index = m_fileListbox.GetCurSel();
	if (index == -1)
	{
		MessageBox(_T("You must first select an entry"));
		return;
	}
	else if (index < count-1)
	{
		CBaseObject* obj = (CBaseObject*)m_fileListbox.GetItemDataPtr(index);
		m_fileListbox.GetText(index, tmpname);
		m_fileListbox.SetItemDataPtr(index, 0);
		m_fileListbox.DeleteString(index);
		m_fileListbox.SetCurSel(m_fileListbox.InsertString(index+1, tmpname));
		m_fileListbox.SetItemDataPtr(index+1, obj);
		m_fileListbox.SetSel(index+1, 1); // reselect the item as moving it un-selects it
	}
	else if (index+1 == count)
		MessageBox(_T("You cannot move the last entry down"));
}

BOOL CBurnCDDlg::doesNameExistinList(CString *filename)
{
	for( int i=0; i<m_fileListbox.GetCount(); i++ )
	{
		
		CBaseObject* pObject = (CBaseObject*)pThis->m_fileListbox.GetItemDataPtr(i);
		ASSERT(pObject != NULL);
		if (pObject == NULL)
			continue;
		if (pObject->GetPath() == *filename)
		{
			if (isDirectory(*filename))
			{
				if (isDirectory(pObject->GetPath()))
					return TRUE;
			}
			else
			{
				if (isDirectory(pObject->GetPath()) == FALSE)
					return TRUE;
			}
		}
	}
	return FALSE;
}


#include "SelectDialog.h"
void CBurnCDDlg::OnBnClickedAddFilesButton()
{
	CSelectDialog ofd(TRUE, _T("*.*"), NULL, OFN_HIDEREADONLY | OFN_ALLOWMULTISELECT,  _T("All files and folders(*.*)|*.*||"), this );
	CString folder = (LPCSTR)GetString("LastAddFilesDir", "");
	ofd.GetOFN().lpstrInitialDir = (LPCSTR)GetString("LastAddFilesDir", "");
	ofd.GetOFN().lpstrTitle = "Select one or more files & folders to add";
	if( ofd.DoModal() != IDOK )
		return;
	int findIndex = ofd.m_SelectedItemList[0].ReverseFind(_T('\\'));
	CString path = ofd.m_SelectedItemList[0].Left(findIndex+1);
	CString tmpstr;
	WriteString("LastAddFilesDir", path);
	int i;
	for(i=0; i<ofd.m_SelectedItemList.GetCount(); i++ )
	{
		if (isDirectory(ofd.m_SelectedItemList[i]))
		{
			if (doesNameExistinList(&ofd.m_SelectedItemList[i]))
			{
				tmpstr.Format("The folder: %s already exists in the list.\n\nAre you sure you want to add it again?", ofd.m_SelectedItemList[i]);

				if (MessageBox(tmpstr, "Are you sure?", MB_ICONQUESTION|MB_YESNO) == IDNO)
					continue;
			}
			CDirObject* pDirObject = new CDirObject(ofd.m_SelectedItemList[i]);
			int addIndex = m_fileListbox.AddString(pDirObject->GetName());
			m_fileListbox.SetItemDataPtr(addIndex, pDirObject);
		}
		else
		{
			if (doesNameExistinList(&ofd.m_SelectedItemList[i]))
			{
				tmpstr.Format("The file: %s already exists in the list.\n\nAre you sure you want to add it again?", ofd.m_SelectedItemList[i]);

				if (MessageBox(tmpstr, "Are you sure?", MB_ICONQUESTION|MB_YESNO) == IDNO)
					continue;
			}
			CFileObject* pFileObject = new CFileObject(ofd.m_SelectedItemList[i]);
			int addIndex = m_fileListbox.AddString(pFileObject->GetName());
			m_fileListbox.SetItemDataPtr(addIndex, pFileObject);	
		}
		if (i==0)
			UpdateCapacity();
		else
			UpdateCapacity(TRUE);
		EnableBurnButton();
//	CFileDialog fileDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT, _T("All Files (*.*)|*.*||"), NULL, 0);
//	CString fileName;
//	const int c_cMaxFiles = 100;
//	const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
//	fileDialog.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
//	fileDialog.GetOFN().nMaxFile = c_cbBuffSize;
//	fileDialog.GetOFN().lpstrTitle = "Select one or more files & folders to add";
//	if (fileDialog.DoModal() == IDOK)
//	{
//		POSITION pos = fileDialog.GetStartPosition();
//		do
//		{
//			CFileObject* pFileObject = new CFileObject(fileDialog.GetNextPathName(pos));
//			int addIndex = m_fileListbox.AddString(pFileObject->GetName());
//			m_fileListbox.SetItemDataPtr(addIndex, pFileObject);	
//		}while(pos > 0);
//		UpdateCapacity();
//		EnableBurnButton();
	}
}

void CBurnCDDlg::OnBnClickedAddFolderButton()
{
	BROWSEINFO bi = {0};
	bi.hwndOwner = m_hWnd;
	bi.ulFlags = BIF_NONEWFOLDERBUTTON |BIF_RETURNONLYFSDIRS;//|BIF_USENEWUI;
	LPITEMIDLIST lpidl = SHBrowseForFolder(&bi);

	if (!lpidl)
		return;
	SetWaitCursor(TRUE);
	//m_TotalSizeText.SetWindowText("Checking folder");
	TCHAR selectedPath[_MAX_PATH] = {0};
	if (SHGetPathFromIDList(lpidl, selectedPath))
	{
		CDirObject* pDirObject = new CDirObject(selectedPath);
		int addIndex = m_fileListbox.AddString(pDirObject->GetName());
		m_fileListbox.SetItemDataPtr(addIndex, pDirObject);
		UpdateCapacity();
		EnableBurnButton();
	}
	SetWaitCursor(FALSE);
}

void CBurnCDDlg::OnDestroy()
{
	CDialog::OnDestroy();
}

void CBurnCDDlg::InitGraphDataVariables()
{
	m_datasectors = 0;
	m_MediaCapacity = 0;
	m_cmediatype = "";
	m_mediatype = GetCurrentMediaType();
	m_cmediatype = GetMediaTypeString(m_mediatype);
	m_MediaSpeeds.GetLBText(1, m_MaxSpeed);
	m_MediaSpeeds.GetLBText(m_MediaSpeeds.GetCurSel(), m_SelectedSpeed);
	m_MediaCapacity = GetFreeSectors();
}

void CBurnCDDlg::OnBnClickedBurnButton()
{
	m_BurnButtonClicked = 1;
	SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)""); //clear status line
	if (m_bWaitingForDisc)//user cancelled multiple burn while waiting for next disc
	{
		SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Multiple copy mode cancelled");
		m_bWaitingForDisc = false;
		UpdateData();
		EnableUI(true);	
		return;
	}
	if (m_nCurrentMode != PROGRAM_IDLE) //user cancelled while burning
	{
		if (m_nCurrentMode == ISOFROM_DISC) //cancel iso from disc
			SetCancelISOFromDisc(true);
		else if (m_FileSystemCombo.GetCurSel() == FS_AUDIOCD || m_FileSystemCombo.GetCurSel() == FS_AUDIOCD_DAO) //cancel audio burn
			SetCancelAudioBurning(true);
		else if (m_nCurrentMode == BURNING_DISC)//cancel normal burn
			SetCancelBurning(true);
		else if (m_nCurrentMode == ERASING_DISC)//cancel erase disc
			SetCancelErasing(true);
		SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Burn Cancel request acknowledged");
	}
	else
	{
		m_Burn.SetIcon(m_stop);
		FREETOOL(IDC_BURN_BUTTON));
		ADDTOOL(IDC_BURN_BUTTON),_T("Attempts to cancel the burning process"));
		UpdateData(FALSE);
		InitGraphDataVariables();

		IMAPI_FORMAT2_DATA_MEDIA_STATE state;   //***//
		HRESULT hr = GetMediaState(&state);//Get media state
		if (SUCCEEDED(hr)) 
		{
			if (isMediaBlank() == FALSE && !(state & IMAPI_FORMAT2_DATA_MEDIA_STATE_APPENDABLE)) //is media blank or appendable
			{
				if (MessageBox("The disc is not blank nor appendable, are you sure you want to continue?", "Are you sure?", MB_ICONQUESTION|MB_YESNO) == IDNO)
				{
					SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Burn cancelled");
					m_bWaitingForDisc = false;
					UpdateData();
					EnableUI(true);	
					return;
				}
			}
		}
		if (m_FileSystemCombo.GetCurSel() == FS_AUDIOCD || m_FileSystemCombo.GetCurSel() == FS_AUDIOCD_DAO) //if audio cd burn
			SetCancelAudioBurning(false); //cancel set not cancel flag for audio
		else
			SetCancelBurning(false);	  //cancel set not cancel flag for burn
		OnSelchangeComboMediaSpeeds();  //set writing speed
		int itemCount = m_fileListbox.GetCount();
		if (itemCount == 1)
		{
			CString fname, ext;
			m_fileListbox.GetText(0, fname);
			int findIndex = fname.ReverseFind(_T('.'));
			ext = fname.Mid(findIndex+1);
			ext.MakeLower();
			if (ext == "iso"  || ext == "bin")
			{	
				if (m_RadioBurnFilesFolders == 0)
				{
					if (MessageBox("You have chosen an image file.\n\nDo you want to burn this as an Image", "Burn as Image?", MB_ICONQUESTION|MB_YESNO) == IDYES)
					{
						m_RadioBurnFilesFolders = 1;
						m_closeMedia.SetCheck(BST_CHECKED);
						UpdateData(FALSE);
						OnRadioburniso();
					}
				}
			}	
		}

		//Start Nic changes to burn ISO file
		if (m_RadioBurnFilesFolders == 1) // if iso write
		{
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
			{
				MessageBox("You cannot write an Image file to a Hard Disk, please choose a different device to write the image to", "Wrong destination device", MB_ICONEXCLAMATION);
				return;
			}
			m_nCurrentMode = WRITING_ISO;
			int itemCount = m_fileListbox.GetCount();
			if (itemCount != 1)
			{
				MessageBox(_T("Error, wrong number of files,  only one Image file can be written"), _T("Wrong number of files"), MB_ICONSTOP);
				return;
			}
			CBaseObject* pObject = (CBaseObject*)m_fileListbox.GetItemDataPtr(0);
			ASSERT(pObject != NULL);
			if (pObject == NULL)
				return;
			ISOfile = pObject->GetPath();
			int findIndex = ISOfile.ReverseFind(_T('.'));
			CString ext = ISOfile.Mid(findIndex+1);
			ext.MakeLower();
			if (ext == "iso" )
				AfxBeginThread(WriteISOThread, this, THREAD_PRIORITY_NORMAL);
			else if (ext == "bin")
				AfxBeginThread(WriteBinThread, this, THREAD_PRIORITY_NORMAL);
		}
		else 
		{
			 if (m_FileSystemCombo.GetCurSel() == FS_AUDIOCD) //if TAO audio
			 {
				 IMAPI_MEDIA_PHYSICAL_TYPE type = GetCurrentMediaType();
				 if (type != IMAPI_MEDIA_TYPE_CDR && type != IMAPI_MEDIA_TYPE_CDRW)
				 {
					CString str;
					str.Format("The disc in the drive is a %s.\nMusic discs can only be made on CD-R or CD-RW", GetMediaTypeString(type));
					MessageBox(str);
					EjectDrive();
					return;
				 }
				 m_nCurrentMode = AUDIOCD_DISC;
				 m_progressTrackText.EnableWindow(TRUE);
				 if (m_VerifyCombo.GetCurSel() == 2)
				 {
					MessageBox(_T("Music CD write does not support Full Verify.  It will be altered to 'Quick' for you."), _T("Full verify not supported"), MB_ICONEXCLAMATION);
					m_VerifyCombo.SetCurSel(1);
					UpdateData(FALSE);
				 }
				 AfxBeginThread(AudioThread, this, THREAD_PRIORITY_NORMAL);
			 }
			 else if (m_FileSystemCombo.GetCurSel() == FS_AUDIOCD_DAO) //else if DAO audio
			 {
				  IMAPI_MEDIA_PHYSICAL_TYPE type = GetCurrentMediaType();
				 if (type != IMAPI_MEDIA_TYPE_CDR && type != IMAPI_MEDIA_TYPE_CDRW)
				 {
					CString str;
					str.Format("The disc in the drive is a %s.\nMusic discs can only be made on CD-R or CD-RW", GetMediaTypeString(type));
					MessageBox(str);
					EjectDrive();
					return;
				 }
				 m_nCurrentMode = AUDIOCD_DAO;
				 m_progressTrackText.EnableWindow(TRUE);
				 if (m_VerifyCombo.GetCurSel() == 2)
				 {
					MessageBox(_T("Music CD write does not support Full Verify.  It will be altered to 'Quick' for you."), _T("Full verify not supported"), MB_ICONEXCLAMATION);
					m_VerifyCombo.SetCurSel(1);
					UpdateData(FALSE);
				 }
				 AfxBeginThread(AudioDAOThread, this, THREAD_PRIORITY_NORMAL);
			 }
			 else if (m_deviceComboBox.GetCurSel() == m_deviceComboBox.GetCount()-1) // else if HDD write iso
			 {
				 m_nCurrentMode = WRITING_ISO;
				AfxBeginThread(WriteISOHddThread, this, THREAD_PRIORITY_NORMAL);
			 }
			 else	//else normal burn thread							
			 {
				 m_nCurrentMode = BURNING_DISC;
				 AfxBeginThread(BurnThread, this, THREAD_PRIORITY_NORMAL);
			 }
		}
	}
	UpdateData();
	EnableUI(false);	
}

int CBurnCDDlg::isMediaLoaded()
{
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return FALSE;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		IMAPI_MEDIA_PHYSICAL_TYPE value;
		HRESULT hRes = pIDiscFormatData->get_CurrentPhysicalMediaType(&value);
		CString media;
		if (hRes == S_OK && value != IMAPI_MEDIA_TYPE_UNKNOWN)
		{
			return TRUE;
		}
	}
	return FALSE; 
}

BOOL CBurnCDDlg::GetVolumeName(CString* str)
{
	HRESULT hr = S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CString dletter = discRecorder->GetVolumePath(0);
		dletter += ":\\";
		DWORD serial, complength, flags;
		CString fs;
		if (GetVolumeInformation(dletter, str->GetBuffer(126), 126, &serial, &complength, &flags, fs.GetBuffer(MAX_PATH+1), MAX_PATH+1))
		{
			str->ReleaseBuffer();
			fs.ReleaseBuffer();
			return 1;
		}
		str->ReleaseBuffer();
		fs.ReleaseBuffer();			
	}
	return 0;
}

BOOL CBurnCDDlg::GetVolumeName()
{
	HRESULT hr = S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CString dletter = discRecorder->GetVolumePath(0);
		dletter += ":\\";
		DWORD serial, complength, flags;
		CString fs;
		if (GetVolumeInformation(dletter, m_volumeLabel.GetBuffer(126), 126, &serial, &complength, &flags, fs.GetBuffer(MAX_PATH+1), MAX_PATH+1))
		{
			m_volumeLabel.ReleaseBuffer();
			fs.ReleaseBuffer();
			return 1;
		}
		m_volumeLabel.ReleaseBuffer();
		fs.ReleaseBuffer();			
	}
	return 0;
}

HRESULT CBurnCDDlg::GetMediaState(IMAPI_FORMAT2_DATA_MEDIA_STATE* state)
{
	HRESULT hr = S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return FALSE;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		hr = pIDiscFormatData->get_CurrentMediaStatus(state);
	}
	return hr; 
}

int CBurnCDDlg::isMediaBlank()
{
	VARIANT_BOOL varbool = VARIANT_TRUE;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return FALSE;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		IMAPI_MEDIA_PHYSICAL_TYPE value;
		HRESULT hRes = pIDiscFormatData->get_CurrentPhysicalMediaType(&value);
		if (hRes == S_OK)
		{
			if (value == IMAPI_MEDIA_TYPE_BDRE || value == IMAPI_MEDIA_TYPE_DVDPLUSRW || value == IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER ||  value == IMAPI_MEDIA_TYPE_DVDRAM ||  value == IMAPI_MEDIA_TYPE_HDDVDRAM)//VARIANT_TRUE = BLANK
			{
				pThis->pIDiscFormatData->get_MediaHeuristicallyBlank(&varbool);
			}
			else if (value == IMAPI_MEDIA_TYPE_UNKNOWN)
				return -1;
			else
			{
				pThis->pIDiscFormatData->get_MediaPhysicallyBlank(&varbool);
			}
		}
		else
			return -1;
		if (varbool == VARIANT_TRUE)
			return 1;
	}		
	return 0;
}

void CBurnCDDlg::OnClickedErase()
{ 
	if (m_nCurrentMode == ERASING_DISC)
	{
		SetCancelErasing(true);
	}
	else
	{
		if (isMediaLoaded() == FALSE)
		{
			MessageBox("No Media Loaded", "Error", MB_ICONSTOP);
			return;
		}
		SetCancelErasing(false);
		//m_isErasing = true;
		m_nCurrentMode = ERASING_DISC;
		UpdateData();
		EnableUI(false);
		m_progressCtrl.SetRange32(0, 100);
		m_progressCtrl.SetPos(0);
		// Clear the taskbar progress bar.
		 if ( m_pTaskbarList )
			m_pTaskbarList->SetProgressState ( m_hWnd, TBPF_NOPROGRESS );
		AfxBeginThread(EraseThread, this, THREAD_PRIORITY_NORMAL);
	}
}

void CBurnCDDlg::OnClickedIsodisc()
{
	if (m_nCurrentMode == ISOFROM_DISC)
	{
		SetCancelISOFromDisc(true);
	}
	else
	{
		if (isMediaLoaded() == FALSE)
		{
			MessageBox("No Media Loaded", "Error", MB_ICONSTOP);
			return;
		}
		OPENFILENAME ofn;
		if (SaveFiles(pThis->m_hWnd, &ofn, "Choose a FileName and path for the Image File", NULL,
				  "ISO Files (*.iso)\0*.iso\0All Files (*.*)\0*.*\0\0",
				  "Last ISOSAVE Directory", ISOSaveFolder.GetBuffer(MAX_PATH), 
				  MAX_PATH, NULL, NULL, OFN_EXPLORER+OFN_HIDEREADONLY, "iso") == false)
		{
			ISOSaveFolder.ReleaseBuffer();
			return;
		}
		ISOSaveFolder.ReleaseBuffer();
		SetCancelISOFromDisc(false);
		m_nCurrentMode = ISOFROM_DISC;
		UpdateData();
		EnableUI(false);
		m_progressCtrl.SetRange32(0, 100);
		m_progressCtrl.SetPos(0);
		// Clear the taskbar progress bar.
		 if ( m_pTaskbarList )
			m_pTaskbarList->SetProgressState ( m_hWnd, TBPF_NOPROGRESS );
		AfxBeginThread(CreateISOFromDiscThread, this, THREAD_PRIORITY_NORMAL);
	}
}


void CBurnCDDlg::SetWaitCursor(BOOL on)
{
	if (on)
		AfxGetApp()->DoWaitCursor(1); // 1->>display the hourglass cursor
	else
		AfxGetApp()->DoWaitCursor(-1); // 1->>display the normal cursor
}

void CBurnCDDlg::EjectDrive()
{
	int selectedIndex = m_deviceComboBox.GetCurSel();
	ASSERT(selectedIndex >= 0);
	if (selectedIndex < 0)
	{
		MessageBox("Error: No Device Selected", "Fatal Error", MB_ICONSTOP);
		return;
	}
	CDiscRecorder* pOrigDiscRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (pOrigDiscRecorder == NULL)
	{
		// This should never happen
	   MessageBox("Error: No Data for selected device", "Fatal Error", MB_ICONSTOP);
	   return;
	}
	pOrigDiscRecorder->EjectMedia();
}

UINT CBurnCDDlg::BurnThread(LPVOID pParam)
{
	CBurnCDDlg* pThis = (CBurnCDDlg*)pParam;
	pThis->m_LayerBreak = pThis->GetLayer0End();
	//pThis->GetDlgItem(IDC_ERASE)->EnableWindow(FALSE);
	// Get the selected recording device from the combobox
	int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	ASSERT(selectedIndex >= 0);
	if (selectedIndex < 0)
	{
		pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Error: No Device Selected"));
		return 0;
	}
	IMAPI_MEDIA_PHYSICAL_TYPE mediaType = pThis->GetCurrentMediaType();
	CDiscRecorder* pOrigDiscRecorder = 
		(CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (pOrigDiscRecorder == NULL)
	{
		// This should never happen
		pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Error: No Data for selected device"));
		return 0;
	}

	// Did user cancel?
	if (pThis->GetCancelBurning())
	{
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Burning cancelled"));
		return 0;
	}

	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Preparing burner..."));
	// Create another disc recorder because we're in a different thread
	CDiscRecorder discRecorder;
	CDiscFormatData discFormatData;
	int nUDFRev = -1;      
	CString errorMessage;
	if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
	{
		if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
		{
			if (discFormatData.Initialize(&discRecorder, CLIENT_NAME))
			{
				
//				IWriteEngine2*	pWriteEngine2;
//				HRESULT hr = CoCreateInstance(__uuidof(MsftWriteEngine2), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWriteEngine2), (void**)&pWriteEngine2);
//				if (SUCCEEDED(hr))
//				{
//					VARIANT_BOOL varbool = VARIANT_FALSE; //use Write10
//					if (mediaType == IMAPI_MEDIA_TYPE_BDR || mediaType == IMAPI_MEDIA_TYPE_BDRE)
//						varbool = VARIANT_TRUE; // use Write12
//					hr = pWriteEngine2->put_UseStreamingWrite12(varbool);
//					if (SUCCEEDED(hr))
//					{
//						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Write12 Streaming selected"));
//					}
//				}
				// Get the media type currently in the recording device
			   // IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
				//discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
					
				// Create the file system
				IStream* dataStream = NULL;
				int nFileSystem = pThis->GetFileSystem();
				if (nFileSystem == FSi_AUDIOCD || nFileSystem == FSi_AUDIOCD_DAO)
				{
					//This should never occur
					pThis->MessageBox("Fatal Error, Audio CD filesystem chosen for data disc");
					return 0;
				}
				if (nFileSystem == FS_AUTO)
				{
					nFileSystem = pThis->m_nAutoFileSystem;
					if (nFileSystem == -1)
					{
						nFileSystem = FsiFileSystemUDF;
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("UDF File System Auto selected"));
					}
				}
				if (nFileSystem & FsiFileSystemUDF)
				{
					nUDFRev = pThis->GetUDFRevision();
					{
						if (nUDFRev = UDF_AUTO)
						{
							nUDFRev = pThis->m_AutoUDFVersion;
						}
					}
				}
				pThis->pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
				
				IMAPI_FORMAT2_DATA_MEDIA_STATE state = IMAPI_FORMAT2_DATA_MEDIA_STATE_UNKNOWN;
				//HRESULT hRes = pThis->GetMediaState(&state);
				HRESULT hRes = pThis->pIDiscFormatData->get_CurrentMediaStatus(&state);
				VARIANT_BOOL varbool = VARIANT_TRUE;
				pThis->pIDiscFormatData->get_MediaHeuristicallyBlank(&varbool);
				SAFEARRAY *multiSession = NULL;
				pThis->pIDiscFormatData->get_MultisessionInterfaces(&multiSession);
				if (pThis->m_bMulti.GetCheck() == BST_UNCHECKED && state & IMAPI_FORMAT2_DATA_MEDIA_STATE_APPENDABLE && !varbool)
				{
					BOOL bQuickErase = 0;
					CMessageClassDlg dlg;
					{
						dlg.SetIconQuestionMark();
						dlg.SetTitleText("Selected Multisession?");
						dlg.EnableOKButton(TRUE);
						dlg.SetText("The disc is multisession and 'Continue Multisession' is not selected and you could lose data.\n\nDo you want me to select it for you?");
						dlg.SetLeftText("Yes");
						dlg.SetRightText("No");
						dlg.SetMiddleText("Cancel");
						dlg.SetDoNotShow(FALSE);
						UINT response = (UINT)dlg.DoModal();
						if ( response == CMessageClassDlg::LEFTBTN)//Yes Response
						{
							pThis->m_bMulti.SetCheck(BST_CHECKED);
							pThis->SendMessage(WM_UPDATEDATA, 0, 0); //This is a way to call UpdateData() from a thread, as you cannot call it from a thread.
						}
						else if ( response == CMessageClassDlg::MIDDLEBTN) //Cancel
						{
							errorMessage.Format(_T("Burn cancelled as requested"),
							pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)errorMessage));
							return 0;
						}
						
					}
				}
				if (!CreateMediaFileSystem(pThis, mediaType, &dataStream, (FsiFileSystems)nFileSystem, nUDFRev, varbool, multiSession))
				{	// CreateMediaFileSystem reported error to UI
					pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"Create Media File System Failed");
					return false;
				}

				discFormatData.SetCloseMedia(pThis->m_closeMedia.GetCheck() ? true : false);
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Burning..."));
				// Burn the data, this does all the work
				IBurnVerification *burnVerifier = NULL;
				HRESULT hr = pThis->pIDiscFormatData->QueryInterface(IID_PPV_ARGS(&burnVerifier));
				if (SUCCEEDED(hr))
				{
					IMAPI_BURN_VERIFICATION_LEVEL   VerificationLevel = (IMAPI_BURN_VERIFICATION_LEVEL)pThis->m_VerifyCombo.GetCurSel();
					hr = burnVerifier->put_BurnVerificationLevel(VerificationLevel);
				}
				pThis->start = clock();

				pThis->SpeedVector.clear();
				pThis->SectorVector.clear();
				pThis->RateVector.clear();
				pThis->BufferVector.clear();
				pThis->CPUVector.clear();
				pThis->m_SaveIBG.EnableWindow(FALSE);
				discFormatData.Burn(pThis->m_hWnd, dataStream);
				// Release the IStream after burning
				dataStream->Release();
				if (burnVerifier != NULL)
				{
					burnVerifier->Release();
					burnVerifier = NULL;
				}
				
				CString num;
				pThis->m_NumberofCopies.GetWindowTextA(num.GetBuffer(10), 10);
				num.ReleaseBuffer();
				if (atoi(num) > 1)// || pThis->m_nNumberofCopies > 1
				{
					discRecorder.EjectMedia();
					if (pThis->m_nNumberofCopies > 1)
					{
						pThis->DoNextCopy();
						discRecorder.ReleaseExclusiveAccess();
						return 0;
					}
				}
				// Eject Media if they chose
				if (pThis->m_ejectWhenFinished.GetCheck())
				{
					discRecorder.EjectMedia();

				}
			}
			discRecorder.ReleaseExclusiveAccess();
			// Finished Burning, GetHresult will determine if it was successful or not
			pThis->SendMessage(WM_BURN_FINISHED, discFormatData.GetHresult(), (LPARAM)(LPCTSTR)discFormatData.GetErrorMessage());
		}
		else
		{
			errorMessage.Format(_T("Failed: %s is exclusive owner"),
				(LPCTSTR)discRecorder.ExclusiveAccessOwner());
			pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
		}
	}
	else
	{
		errorMessage.Format(_T("Failed to prepare burner - Unique ID:%s"),
			(LPCTSTR)pOrigDiscRecorder->GetUniqueId());
		pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
	}
	return 0;
}

#include "DiscFormatErase.h"
UINT CBurnCDDlg::EraseThread(LPVOID pParam)
{
	CBurnCDDlg* pThis = (CBurnCDDlg*)pParam;
	pThis->GetDlgItem(IDC_ERASE)->EnableWindow(FALSE);
	//Get Full or quick
	BOOL bQuickErase = 0;
	CMessageClassDlg dlg;
	{
		dlg.SetIconQuestionMark();
		dlg.SetTitleText("Quick or Full erase?");
		dlg.EnableOKButton(TRUE);
		dlg.SetText("Would you like a quick erasure or a full erasure?  Full may take a considerable time.");
		dlg.SetLeftText("Quick");
		dlg.SetRightText("Cancel");
		dlg.SetMiddleText("Full");
		dlg.SetDoNotShow(FALSE);
		UINT response = (UINT)dlg.DoModal();
		if ( response == 1)//Quick Response
			bQuickErase = TRUE;
		else if ( response == 0) //Full Response
			bQuickErase = FALSE;
		else//cancel selected
		{
			pThis->SendMessage(WM_ERASE_FINISHED, -2, (LPARAM)_T("Erase cancelled"));
			return 0;  
		}
	}
	// Get the selected recording device from the combobox
	int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	ASSERT(selectedIndex >= 0);
	if (selectedIndex < 0)
	{
		pThis->SendMessage(WM_ERASE_FINISHED, 0, (LPARAM)_T("Error: No Device Selected"));
		return 0;
	}
	CDiscRecorder* pOrigDiscRecorder = (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	// Did user cancel?
	if (pThis->GetCancelErasing())
	{
		pThis->SendMessage(WM_ERASE_FINISHED, -2, (LPARAM)_T("Erase cancelled"));
		return 0;
	}
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Preparing to Erase..."));
	// Create another disc recorder because we're in a different thread
	CDiscRecorder discRecorder;
	CString errorMessage;
	if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
	{
		CDiscFormatErase discFormatErase;	
		if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
		{
			if (discFormatErase.Initialize(&discRecorder, CLIENT_NAME))
			{
				// Get the media type currently in the recording device
				//IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
				//discFormatErase.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
				// Erase the data
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Erasing Media..."));
				CString clientname=CLIENT_NAME;

				discFormatErase.Erase(pThis->m_hWnd, bQuickErase ? VARIANT_FALSE : VARIANT_TRUE);
				// Eject Media if they chose
				if (pThis->m_ejectWhenFinished.GetCheck())
				{
					discRecorder.EjectMedia();	
				}
				discRecorder.ReleaseExclusiveAccess();
				discFormatErase.GetIDiscFormat2ErasePtr()->put_Recorder(NULL);
			}
			else
			{
				errorMessage.Format(_T("Failed: to initialize"));
				pThis->SendMessage(WM_ERASE_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
			}
		}
		else
		{
			errorMessage.Format(_T("Failed: %s is exclusive owner"), (LPCTSTR)discRecorder.ExclusiveAccessOwner());
			pThis->SendMessage(WM_ERASE_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
		}
		// Finished Erasing, GetHresult will determine if it was successful or not
		pThis->SendMessage(WM_ERASE_FINISHED, discFormatErase.GetHresult(), (LPARAM)(LPCTSTR)discFormatErase.GetErrorMessage());
	}
	else
	{
		errorMessage.Format(_T("Failed to prepare recorder - Unique ID:%s"), (LPCTSTR)pOrigDiscRecorder->GetUniqueId());
		pThis->SendMessage(WM_ERASE_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
	}
	return 0;
}

HRESULT CBurnCDDlg::GetCDImageCreatorInterface(IRawCDImageCreator** raw)
{
	return CoCreateInstance(CLSID_MsftRawCDImageCreator, NULL, CLSCTX_ALL, __uuidof(IRawCDImageCreator), (void**)raw);

}

/////////////////////////////////////////////////////////////////////////////
//
// CBurnCDDlg::CreateMediaFileSystem
//
// Description
//		Creates an IStream used to 
//
#include "globals.h"
bool CBurnCDDlg::CreateFileSystemForISO(CBurnCDDlg* pThis, IStream** ppDataStream, FsiFileSystems nFileSystem, LONG UDFVersion)
{
	IFileSystemImage*		image = NULL;
	IFileSystemImageResult*	imageResult = NULL;
	IFsiDirectoryItem*		rootItem = NULL;
	IBootOptions*			pBootOptions = NULL;
	IStream*				bootStream = NULL;
	CString					message;
	bool					returnVal = false;
	HRESULT hr = S_OK;
	if (GetOSVersion() < WINDOWSVISTA)
		hr = CoCreateInstance(CLSID_MsftFileSystemImage, NULL, CLSCTX_ALL, __uuidof(IFileSystemImage), (void**)&image);
	else
		hr = CoCreateInstance(CLSID_MsftFileSystemImage, NULL, CLSCTX_ALL, __uuidof(IFileSystemImage3), (void**)&image);
	if (FAILED(hr) || (image == NULL))
	{
		pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed to create IFileSystemImage Interface"));
		return false;
	}
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Creating File System..."));
	IMAPI_MEDIA_PHYSICAL_TYPE type = IMAPI_MEDIA_TYPE_MAX;
	image->ChooseImageDefaultsForMediaType(type);
	image->put_StageFiles(VARIANT_FALSE);
//	if (nFileSystem == FsiFileSystemUDF && UDFVersion > 0) //UDFVersion == 0 means Auto Selected, so above Choose call will set a default for the media.
//	{
//		hr = image->put_UDFRevision(UDFVersion);
//		if (FAILED(hr))
//		{
//			AfxMessageBox("Chosen UDF version failed,  setting V1.02");
//			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("UDF version failed,  setting V1.02"));
//			image->put_UDFRevision(0x102);
//		}
//	}
	image->put_FileSystemsToCreate(nFileSystem );//(FsiFileSystemJoliet, FsiFileSystemISO9660, FsiFileSystemUDF etc
	image->put_VolumeName(pThis->m_volumeLabel.AllocSysString());
	// Get the image root
	hr = image->get_Root(&rootItem);
	//Do Boot Image stuff
	if (pThis->m_CheckBootable.GetCheck() == BST_CHECKED)
	{
		HRESULT hRes;
		pBootOptions = NULL;
		hRes = CoCreateInstance(CLSID_BootOptions, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pBootOptions));
		if (FAILED(hRes))
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to create bootoptions"));
		}
		if (SUCCEEDED(hRes))
		{
			if (pThis->m_cBootFileName != "")
			{
				USES_CONVERSION;
				CString bootW;
				bootW.Format("\\\\?\\%s", bootW);
				hRes = SHCreateStreamOnFileW(A2CW(pThis->m_cBootFileName), STGM_READ | STGM_SHARE_DENY_WRITE, &bootStream);
				if (FAILED(hRes))
				{
					pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed SHCreateStreamOnFileW"));    
				}
				if (SUCCEEDED(hRes))
				{
					hRes = pBootOptions->AssignBootImage(bootStream);
					if (FAILED(hRes))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed AssignBootImage"));    
					}
				}            
				if (SUCCEEDED(hRes))
				{
					hRes = image->put_BootImageOptions(pBootOptions);
					if (FAILED(hRes))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed BootImage put_BootImageOptions"));    
					}
				}                        
			}
		}
		//End Boot Image stuff
	}
	if (SUCCEEDED(hr))
	{
		// Add Files and Directories to File System Image
		if ( pThis->m_pTaskbarList )
			pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);

		int itemCount = pThis->m_fileListbox.GetCount();
		pThis->m_progressCtrl.SetRange(0, 100);
		pThis->m_progressCtrl.SetPos(0);
		// Clear the taskbar progress bar.
		 if ( pThis->m_pTaskbarList )
			pThis->m_pTaskbarList->SetProgressState (pThis->m_hWnd, TBPF_NOPROGRESS );

		ULONGLONG llProgressSize = 0;
		ULONGLONG divisor = pThis->m_TotalSizeToBurn / 100;
		for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
		{
			CBaseObject* pObject = (CBaseObject*)pThis->m_fileListbox.GetItemDataPtr(itemIndex);
			ASSERT(pObject != NULL);
			if (pObject == NULL)
				continue;

			CString fileName = pObject->GetName();
			message.Format(_T("Adding \"%s\" to file system..."), (LPCTSTR)fileName);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)(LPCTSTR)message);

			if (pObject->IsKindOf(RUNTIME_CLASS(CFileObject)))
			{
				CFileObject* pFileObject = (CFileObject*)pObject;
				IStream* fileStream = pFileObject->GetStream();
				if (fileStream != NULL)
				{
					hr = rootItem->AddFile(pFileObject->GetName().AllocSysString(), fileStream);
					llProgressSize += pFileObject->GetSizeOnDisc();
					pThis->m_progressCtrl.SetPos((short)(llProgressSize/divisor));
					if ( pThis->m_pTaskbarList )
						pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, (short)llProgressSize/divisor, 100 );

					if (FAILED(hr))
					{
						// IMAPI_E_IMAGE_SIZE_LIMIT 0xc0aab120
						message.Format(_T("Failed IFsiDirectoryItem->AddFile(%s)!"), 
							(LPCTSTR)pFileObject->GetName());
						pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)(LPCTSTR)message);
						break;
					}
				}
			}
			else if (pObject->IsKindOf(RUNTIME_CLASS(CDirObject)))
			{
				CDirObject* pDirObject = (CDirObject*)pObject;
				hr = rootItem->AddTree(pDirObject->GetPath().AllocSysString(), VARIANT_TRUE);
				llProgressSize += pDirObject->GetSizeOnDisc();
				pThis->m_progressCtrl.SetPos((short)(llProgressSize/divisor));
				if ( pThis->m_pTaskbarList )
				pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, (short)llProgressSize/divisor, 100 );

				if (FAILED(hr))
				{
					// IMAPI_E_IMAGE_SIZE_LIMIT 0xc0aab120
					message.Format(_T("Failed IFsiDirectoryItem->AddTree(%s)!"), 
						(LPCTSTR)pDirObject->GetName());
					pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)(LPCTSTR)message);
					break;
				}
			}
			// Did user cancel?
			if (pThis->GetCancelBurning())
			{
				pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Make ISO cancelled"));
				hr = IMAPI_E_FSI_INTERNAL_ERROR;
			}		
		}
		if (SUCCEEDED(hr))
		{
			// Create the result image
			hr = image->CreateResultImage(&imageResult);
			if (SUCCEEDED(hr))
			{
				// Get the stream
				hr = imageResult->get_ImageStream(ppDataStream);
				if (SUCCEEDED(hr))
				{
					pThis->m_progressCtrl.SetPos(0);
					// Clear the taskbar progress bar.
					if ( pThis->m_pTaskbarList )
						pThis->m_pTaskbarList->SetProgressState ( pThis->m_hWnd, TBPF_NOPROGRESS );
					returnVal = true;
				}
				else
				{
					pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed IFileSystemImageResult->get_ImageStream!"));
				}

			}
			else
			{
				pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed IFileSystemImage->CreateResultImage!"));
			}
		}
	}
	else
	{
		pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed IFileSystemImage->getRoot"));
	}
	// Cleanup
	if (pBootOptions != NULL)
		pBootOptions->Release();
	if (image != NULL)
		image->Release();
	if (imageResult != NULL)
		imageResult->Release();
	if (rootItem != NULL)
		rootItem->Release();
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("ISO preparation complete..."));
	return returnVal;
}

#include "DFileSystemImage.h"
/////////////////////////////////////////////////////////////////////////////
bool CBurnCDDlg::CreateMediaFileSystem(CBurnCDDlg* pThis, IMAPI_MEDIA_PHYSICAL_TYPE mediaType, IStream** ppDataStream, FsiFileSystems nFileSystem, LONG UDFVersion, VARIANT_BOOL isBlank, SAFEARRAY*multiSession )
{
	CDFileSystemImage fileSystemImage;
	IFileSystemImage* pfileSystemImage;
	//IFileSystemImage*		image = NULL;
	IFileSystemImageResult*	imageResult = NULL;
	IFsiDirectoryItem*		rootItem = NULL;
	IBootOptions*			pBootOptions = NULL;
	IStream*				bootStream = NULL;
	CString					message;
	bool					returnVal = false;
	HRESULT hr = S_OK;
	//if (GetOSVersion() < WINDOWSVISTA)
	//	hr = CoCreateInstance(CLSID_MsftFileSystemImage, NULL, CLSCTX_ALL, __uuidof(IFileSystemImage), (void**)&image);
	//else
	//	hr = CoCreateInstance(CLSID_MsftFileSystemImage, NULL, CLSCTX_ALL, __uuidof(IFileSystemImage3), (void**)&image);
	//if (FAILED(hr) || (image == NULL))
	//{
	//	pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed to create IFileSystemImage Interface"));
	//	return false;
	//}
	if (!fileSystemImage.Initialize())
	{
		AfxMessageBox("Failure to open IFileSystemImage  interface");
		return false;
	}
	pfileSystemImage = fileSystemImage.GetFileSystemImagePtr();
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Creating File System..."));
	pfileSystemImage->ChooseImageDefaultsForMediaType(mediaType);
	pfileSystemImage->put_StageFiles(VARIANT_FALSE);
	if (nFileSystem & FsiFileSystemUDF && UDFVersion > 0) //UDFVersion == 0 means Auto Selected, so above Choose call will set a default for the media.
	{
		hr = pfileSystemImage->put_UDFRevision(UDFVersion);
		if (FAILED(hr))
		{
			AfxMessageBox("Chosen UDF version failed,  setting V1.02");
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("UDF version failed,  setting V1.02"));
			pfileSystemImage->put_UDFRevision(0x102);
		}
	}
	pfileSystemImage->put_FileSystemsToCreate(nFileSystem );//(FsiFileSystemJoliet, FsiFileSystemISO9660, FsiFileSystemUDF etc
	///////////////////////////////
	/*  start multisession import*/
	//***/////////////////////////////
	if (pThis->m_bMulti.GetCheck() == BST_UNCHECKED && !isBlank)
	{
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("previous session data will be lost"));
	}
	if (pThis->m_bMulti.GetCheck() == BST_CHECKED)
	{
		FsiFileSystems fileSystems;
		if (multiSession != NULL)
		{
			hr = pfileSystemImage->put_MultisessionInterfaces(multiSession);
			if (FAILED(hr))
			{
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("MultisessionInterfaces Failed"));
				if (multiSession != NULL)
				{
					SafeArrayDestroy(multiSession);
					
				}		
			}
			multiSession = NULL;
		}
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Importing session data..."));
		hr = pfileSystemImage->ImportFileSystem(&fileSystems);
		if (FAILED(hr))
		{
			if (hr == IMAPI_E_EMPTY_DISC)
			{
				 pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Disc is Empty"));
				 hr = S_OK;
			}
			else
			{
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, hr, (LPARAM)_T("Failed to Import session"));
			}
		}
		///////////////////////////////////
		/*End Mulisession import*/
		///////////////////////////////////
	}
	pfileSystemImage->put_VolumeName(pThis->m_volumeLabel.AllocSysString());
	// Get the image root
	hr = pfileSystemImage->get_Root(&rootItem);
	//Do Boot Image stuff
	if (pThis->m_bMulti.GetCheck() == BST_CHECKED && pThis->m_CheckBootable.GetCheck() == BST_CHECKED)
	{
		pThis->MessageBox("Error,  you cannot make a multisession disc bootable", "Error", MB_ICONSTOP);
		pThis->m_CheckBootable.SetCheck(BST_UNCHECKED);
		pThis->m_cBootFileName.Empty();
		pThis->SendMessage(WM_UPDATEDATA, 0, 0); //This is a way to call UpdateData() from a thread, as you cannot call it from a thread.
	}
	if (pThis->m_CheckBootable.GetCheck() == BST_CHECKED)
	{
		HRESULT hRes;
		pBootOptions = NULL;
		hRes = CoCreateInstance(CLSID_BootOptions, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pBootOptions));
		if (FAILED(hRes))
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to create bootoptions"));
		}
		if (SUCCEEDED(hRes))
		{
			if (pThis->m_cBootFileName != "")
			{
				USES_CONVERSION;
				CString bootW;
				bootW.Format("\\\\?\\%s", bootW);
				hRes = SHCreateStreamOnFileW(A2CW(pThis->m_cBootFileName), STGM_READ | STGM_SHARE_DENY_WRITE, &bootStream);
				if (FAILED(hRes))
				{
					pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed SHCreateStreamOnFileW"));    
				}
				if (SUCCEEDED(hRes))
				{
					hRes = pBootOptions->AssignBootImage(bootStream);
					if (FAILED(hRes))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed AssignBootImage"));    
					}
				}            
				if (SUCCEEDED(hRes))
				{
					hRes = pfileSystemImage->put_BootImageOptions(pBootOptions);
					if (FAILED(hRes))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed BootImage put_BootImageOptions"));    
					}
				}                        
			}
		}
		//End Boot Image stuff
	}
	if (SUCCEEDED(hr))
	{
		//To prevent IMAPI_E_IMAGE_SIZE_LIMIT,  need to put free media blocks so it knows the size it can grow to.
		LONG freeBlocks;
		HRESULT hRes = pThis->pIDiscFormatData->get_FreeSectorsOnMedia(&freeBlocks);
		if (FAILED(hRes))
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to get Free Media Blocks"));
		}
		else
		{
			hRes = pfileSystemImage->put_FreeMediaBlocks(freeBlocks);
			if (FAILED(hRes))
			{
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to get Free Media Blocks"));
			}
		}
		// Add Files and Directories to File System Image
		int itemCount = pThis->m_fileListbox.GetCount();
		pThis->m_progressTrackText.EnableWindow(TRUE);
		pThis->m_progressTrackText.SetWindowText("File Progress:");
		pThis->m_progressCtrl.SetRange(0, 100);
		pThis->m_progressCtrl.SetPos(0);
		// Clear the taskbar progress bar.
		 if ( pThis->m_pTaskbarList )
			pThis->m_pTaskbarList->SetProgressState ( pThis->m_hWnd, TBPF_NOPROGRESS );
		ULONGLONG llProgressSize = 0;
		pThis->m_ProgressTrack.SetRange(0, 100);
		pThis->m_ProgressTrack.SetPos(0);
		ULONGLONG divisor = pThis->m_TotalSizeToBurn / 100;
		fileSystemImage.CreateEvent(pThis->m_hWnd);
		if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
		for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
		{
			CBaseObject* pObject = (CBaseObject*)pThis->m_fileListbox.GetItemDataPtr(itemIndex);
			ASSERT(pObject != NULL);
			if (pObject == NULL)
				continue;
			//CString fileName = pObject->GetName();
			//message.Format(_T("Adding \"%s\" to file system..."), (LPCTSTR)fileName);
			//pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)(LPCTSTR)message);

			if (pObject->IsKindOf(RUNTIME_CLASS(CFileObject)))
			{
				CFileObject* pFileObject = (CFileObject*)pObject;
				IStream* fileStream = pFileObject->GetStream();
				if (fileStream != NULL)
				{
					hr = rootItem->AddFile(pFileObject->GetName().AllocSysString(), fileStream);
					llProgressSize += pFileObject->GetSizeOnDisc();
					pThis->m_progressCtrl.SetPos((short)(llProgressSize/divisor));
					if ( pThis->m_pTaskbarList )
						pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, (short)llProgressSize/divisor, 100);
				
					if (FAILED(hr))
					{
						// IMAPI_E_IMAGE_SIZE_LIMIT 0xc0aab120
						message.Format(_T("Failed IFsiDirectoryItem->AddFile(%s)!"), 
							(LPCTSTR)pFileObject->GetName());
						pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)(LPCTSTR)message);
						break;
					}
				}
				
			}
			else if (pObject->IsKindOf(RUNTIME_CLASS(CDirObject)))
			{
				VARIANT_BOOL vbool = VARIANT_TRUE;
				CDirObject* pDirObject = (CDirObject*)pObject;
				if (itemCount == 1)
				{
					if (pObject->IsKindOf(RUNTIME_CLASS(CDirObject)))
					{
						CString ctmp;
						ctmp.Format("Do you want to include the folder '%s' on the disc?\n\nClick 'Yes' to include the folder\n\nClick 'No' to burn its contents only", pDirObject->GetName());
						if (pThis->MessageBox(ctmp, "Include Folder or contents only?", MB_ICONQUESTION|MB_YESNO) == IDNO)
						{
							vbool = VARIANT_FALSE;
						}
					}
				}
				hr = rootItem->AddTree(pDirObject->GetPath().AllocSysString(), vbool);
				llProgressSize += pDirObject->GetSizeOnDisc();
				pThis->m_progressCtrl.SetPos((short)(llProgressSize/divisor));
				if ( pThis->m_pTaskbarList )
						pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, (short)llProgressSize/divisor, 100);
				if (FAILED(hr))
				{
					// IMAPI_E_IMAGE_SIZE_LIMIT 0xc0aab120
					message.Format(_T("Failed IFsiDirectoryItem->AddTree(%s)!"), 
						(LPCTSTR)pDirObject->GetName());
					pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)(LPCTSTR)message);
					break;
				}
			}
			// Did user cancel?
			if (pThis->GetCancelBurning())
			{
				pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Burning cancelled"));
				hr = IMAPI_E_FSI_INTERNAL_ERROR;
			}
			
		}

		if (SUCCEEDED(hr))
		{
			// Create the result image
			hr = pfileSystemImage->CreateResultImage(&imageResult);
			if (SUCCEEDED(hr))
			{
				// Get the stream
				hr = imageResult->get_ImageStream(ppDataStream);
				if (SUCCEEDED(hr))
				{
					pThis->m_progressCtrl.SetPos(0);
					// Clear the taskbar progress bar.
					if ( pThis->m_pTaskbarList )
						pThis->m_pTaskbarList->SetProgressState ( pThis->m_hWnd, TBPF_NOPROGRESS );
					returnVal = true;
				}
				else
				{
					pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed IFileSystemImageResult->get_ImageStream!"));
				}

			}
			else
			{
				pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed IFileSystemImage->CreateResultImage!"));
			}
		}
	}
	else
	{
		pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed IFileSystemImage->getRoot"));
	}
	// Cleanup
try
{
	pThis->m_progressTrackText.EnableWindow(FALSE);	
	pThis->m_progressTrackText.SetWindowText("Track Progress:");
	fileSystemImage.DeleteEvent();
	if (pBootOptions != NULL)
		pBootOptions->Release();
//	if (image != NULL)
//		image->Release();
	if (imageResult != NULL)
		imageResult->Release();
	if (rootItem != NULL)
		rootItem->Release();
}
catch (CFileException* e)
{
	SAFE_LOG(out, "Error Releasing interfaces...", false);
	SAFE_LOG(out, e, true);
}
	//pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Create Image done..."));
	return returnVal;
}

LRESULT CBurnCDDlg::OnBurnStatusMessage(WPARAM, LPARAM lpMessage)
{
	if (lpMessage != NULL)
	{
		//m_progressText.SetWindowText("    
				m_progressText.SetWindowText((LPCTSTR)lpMessage);
	}
	return 0;
}

void CBurnCDDlg::PlayCompletedSound()
{
	int play = GetInt("Sound", 3);
	if (play > 0)
	{
		if (play == 1)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE1),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 2)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE2),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 3)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE_BELLS_ASCEND),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 4)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE_TADA),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 5)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE_MAGIC),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
	}
}

void CBurnCDDlg::PlayStartupSound()
{
	pThis->SetWaitCursor(FALSE);
	int play = GetInt("SoundStartup", 5);
	if (play > 0)
	{
		if (play == 1)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE1),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 2)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE2),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 3)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE_BELLS_ASCEND),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 4)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE_TADA),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
		else if (play == 5)
			PlaySound(MAKEINTRESOURCE(IDR_WAVE_MAGIC),GetModuleHandle(NULL), SND_RESOURCE|SND_ASYNC);
	}
}

LRESULT CBurnCDDlg::OnEraseFinished(WPARAM hResult, LPARAM lpMessage)
{
	
	if (lpMessage != NULL)
	{
		CString tmp = (LPCTSTR)lpMessage;
		if (tmp == "Erase cancelled")
		{
			m_progressText.SetWindowText(_T(tmp));
			m_bufferText.SetWindowTextA(_T("Buffer Empty"));
			MessageBox(_T(tmp));
		}
		else
		{
			if (SUCCEEDED((HRESULT)hResult))
			{
	
				m_progressCtrl.SetPos(100);
				if ( pThis->m_pTaskbarList )
					pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, 100, 100);

				m_progressText.SetWindowText(_T("Erase Successfully Completed"));
				PlayCompletedSound();
				m_bufferText.SetWindowTextA(_T("Buffer Empty"));
				if (m_CheckShutdown.GetCheck() == 1)
				{
					m_nCurrentMode = PROGRAM_IDLE;
					EnableUI(TRUE);
					ShutDownWindows();
				}
				//else
				//	MessageBox(_T("Erase Successfully Completed"));
			}
			else
			{
				CString errorstr;
				GetImapiErrorString((int)hResult, &errorstr);
				m_progressText.SetWindowText(errorstr);
				MessageBox(errorstr);
			}
		}
	}
	else
	{
		if (SUCCEEDED((HRESULT)hResult))
		{
			m_progressText.SetWindowText(_T("Erase completed successfully!"));
			PlayCompletedSound();
			if (m_CheckShutdown.GetCheck() == 1)
			{
				m_nCurrentMode = PROGRAM_IDLE;
				EnableUI(TRUE);
				ShutDownWindows();
			}
		}
		else
		{
			CString message;
			message.Format(_T("Erase failed! Error: 0x%08x"), hResult);
			m_progressText.SetWindowText(message);
		}
	}
	m_nCurrentMode = PROGRAM_IDLE;
	EnableUI(TRUE);
	//GetDlgItem(IDC_ERASE)->EnableWindow(TRUE);
	return 0;
}

LRESULT CBurnCDDlg::OnImapiUpdate(WPARAM wParam, LPARAM lParam)
{
	//NOTE:  these are done in different switch statements as some of the
	//		 values for each 'case' are the same value, so they needs to
	//		 be split up to prevent error,  but still have them all in 
	//		 in the one function.
	IMAPI_FORMAT2_DATA_WRITE_ACTION currentAction = (IMAPI_FORMAT2_DATA_WRITE_ACTION)wParam;
	PIMAPI_STATUS pImapiStatus = (PIMAPI_STATUS)lParam;
	switch (currentAction)  
	{
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_VALIDATING_MEDIA:
		m_progressText.SetWindowText(_T("Validating current disc..."));
		break;
		break;
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_FORMATTING_MEDIA:
			m_progressText.SetWindowText(_T("Formatting disc..."));
			UpdateTimes(pImapiStatus->totalTime, pImapiStatus->remainingTime);
			UpdateEraseProgress(pImapiStatus->totalTime, pImapiStatus->remainingTime);
			return GetCancelErasing() ? RETURN_CANCEL_WRITE : RETURN_CONTINUE;
		break;	
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_INITIALIZING_HARDWARE:
			m_progressText.SetWindowText(_T("Preparing burner..."));
		break;
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_CALIBRATING_POWER:
			m_progressText.SetWindowText(_T("Calibrating laser power..."));
		break;
	
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_WRITING_DATA:
			UpdateTimes(pImapiStatus->totalTime, pImapiStatus->remainingTime, pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
			UpdateBuffer(pImapiStatus->usedSystemBuffer, pImapiStatus->totalSystemBuffer);
			UpdateProgress(pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
			/*
			LONG startLba;			// the starting lba of the current operation
			LONG sectorCount;		// the total sectors to write in the current operation
			LONG lastReadLba;		// the last read lba address
			LONG lastWrittenLba;	// the last written lba address
			LONG totalSystemBuffer;	// total size of the system buffer
			LONG usedSystemBuffer;	// size of used system buffer
			LONG freeSystemBuffer;	// size of the free system buffer
		*/
		break;
		case IMAPI_WRITE_ENGINE2_ACTION_WRITING_MEDIA:
			UpdateBuffer(pImapiStatus->usedSystemBuffer, pImapiStatus->totalSystemBuffer);
			UpdateProgress(pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
			/*
			LONG startLba;			// the starting lba of the current operation
			LONG sectorCount;		// the total sectors to write in the current operation
			LONG lastReadLba;		// the last read lba address
			LONG lastWrittenLba;	// the last written lba address
			LONG totalSystemBuffer;	// total size of the system buffer
			LONG usedSystemBuffer;	// size of used system buffer
			LONG freeSystemBuffer;	// size of the free system buffer
		*/
		break;
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_VERIFYING:
			m_progressText.SetWindowText(_T("Verifying disc, Please wait..."));
			//UpdateVerifyTimes(pImapiStatus->totalTime, pImapiStatus->remainingTime, pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
			//UpdateVerifyProgress(pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
		break;
		case IMAPI_FORMAT2_DATA_WRITE_ACTION_FINALIZATION:
			m_progressText.SetWindowText(m_closeMedia.GetCheck() ? _T("Finalising Disc (not appendable)"):_T("Finalising session (appendable)"));
			//m_timeLeft.SetWindowText(_T("0:00:00"));
		break;
	}
	return GetCancelBurning() ? RETURN_CANCEL_WRITE : RETURN_CONTINUE;
}

LRESULT CBurnCDDlg::OnImapiRawUpdate(WPARAM wParam, LPARAM lParam)
{
	IMAPI_FORMAT2_RAW_CD_WRITE_ACTION currentAction = (IMAPI_FORMAT2_RAW_CD_WRITE_ACTION)wParam;
	PIMAPI_STATUS pImapiStatus = (PIMAPI_STATUS)lParam;
	switch (currentAction)  
	{			
		case IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_PREPARING:
			m_progressText.SetWindowText(_T("Preparing DAO burn..."));
			UpdateTimes(pImapiStatus->elapsedTime, pImapiStatus->remainingTime, pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
		break;
		case IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_FINISHING:
			m_progressText.SetWindowText(_T("Finishing DAO burn..."));
			UpdateTimes(pImapiStatus->elapsedTime, pImapiStatus->remainingTime, pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
		break;
		case IMAPI_FORMAT2_RAW_CD_WRITE_ACTION_WRITING:
			UpdateTimes(pImapiStatus->elapsedTime, pImapiStatus->remainingTime, pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
			UpdateBuffer(pImapiStatus->usedSystemBuffer, pImapiStatus->totalSystemBuffer);
			UpdateProgress(pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount);
		break;
	}
	return GetCancelBurning() ? RETURN_CANCEL_WRITE : RETURN_CONTINUE;
}

LRESULT CBurnCDDlg::OnImapiAudioUpdate(WPARAM wParam, LPARAM lParam)
{
	
	IMAPI_FORMAT2_TAO_WRITE_ACTION currentAction = (IMAPI_FORMAT2_TAO_WRITE_ACTION)wParam;
	PIMAPI_STATUS pImapiStatus = (PIMAPI_STATUS)lParam;

	switch (currentAction)
	{
	/*
		LONG startLba;			// the starting lba of the current operation
		LONG sectorCount;		// the total sectors to write in the current operation
		LONG lastReadLba;		// the last read lba address
		LONG lastWrittenLba;	// the last written lba address
		LONG totalSystemBuffer;	// total size of the system buffer
		LONG usedSystemBuffer;	// size of used system buffer
		LONG freeSystemBuffer;	// size of the free system buffer
	*/
	case IMAPI_FORMAT2_TAO_WRITE_ACTION_PREPARING:
		m_progressText.SetWindowText(_T("Preparing Audio Write..."));
	break;
	case IMAPI_FORMAT2_TAO_WRITE_ACTION_FINISHING:
		m_progressText.SetWindowText(_T("Closing Disc..."));
		//m_timeLeft.SetWindowText(_T("0:00:00"));
	break;
	case IMAPI_FORMAT2_TAO_WRITE_ACTION_WRITING:
			UpdateTimes(pImapiStatus->elapsedTime, pImapiStatus->remainingTime);
			UpdateAudioBuffer(pImapiStatus->usedSystemBuffer, pImapiStatus->totalSystemBuffer);
			UpdateAudioProgress(pImapiStatus->lastWrittenLba-pImapiStatus->startLba, pImapiStatus->sectorCount, pImapiStatus->currentTrack);
	break;
	}
	
	return GetCancelBurning() ? RETURN_CANCEL_WRITE : RETURN_CONTINUE;
}


LRESULT CBurnCDDlg::OnImapiFsUpdate(WPARAM wParam, LPARAM lParam)
{
	//WM_IMAPI_FS_UPDATE, IMAPI_FILESYSTEM_FILE_UPDATE
	IMAPI_FORMAT2_TAO_WRITE_ACTION currentAction = (IMAPI_FORMAT2_TAO_WRITE_ACTION)wParam;
	PIMAPI_STATUS pImapiStatus = (PIMAPI_STATUS)lParam;

	switch (currentAction)
	{
	/*
		imapiStatus.currentFile = currentFile;
		imapiStatus.copiedSectors = copiedSectors;
		imapiStatus.totalSectors = totalSectors;
	*/
	case IMAPI_FILESYSTEM_FILE_UPDATE:
			UpdateFSProgress(pImapiStatus->currentFile, pImapiStatus->copiedSectors, pImapiStatus->totalSectors);
	break;
	}
	
	return GetCancelBurning() ? RETURN_CANCEL_WRITE : RETURN_CONTINUE;
}


void CBurnCDDlg::UpdateFSProgress(BSTR currentFile, ULONG copiedSectors, ULONG totalSectors)
{
	CString cName, fileprogress;
	_bstr_t bstrIntermediate(currentFile);
	cName.Format(_T("Processing File: %s"),(LPCTSTR)bstrIntermediate);
	SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)cName.GetBuffer(0));
	if (totalSectors && copiedSectors)
	{
		int progress = (copiedSectors*100) / totalSectors;
		m_ProgressTrack.SetPos(progress);
		fileprogress.Format("File Progress: %d%%", progress);
		m_progressTrackText.SetWindowText(fileprogress);			
	}
}

// Set the estimated remaining time
void CBurnCDDlg::UpdateTimes(LONG totalTime, LONG remainingTime, ULONG writtenSectors, ULONG totalSectors)
{
	COleDateTime time = COleDateTime::GetCurrentTime();
	m_ElapsedTime =  time - m_ElapsedStartTime;
	// Set the estimated total time
//	CString strText;
//	int hours, mins, secs;
//	if (totalTime > 0)
//	{
//		hours = totalTime / 3600;
//		mins =  (totalTime % 3600) / 60;
//		secs =  (totalTime % 3600) % 60;
//		strText.Format(_T("%01d:%02d:%02d"), hours, mins, secs);
//	}
//	else
//		strText = _T("0:00:00");
	//m_estimatedTime.SetWindowText(strText);
	// Set the estimated remaining time
//	if (writtenSectors && totalSectors && remainingTime == 0)
//	{
//		int percent = (100*writtenSectors) / totalSectors;
//		if (percent == 99)
//			percent = 100;
//		if (percent)
//		{
//			LONG ouresttime = (totalTime * (100/percent)) - totalTime;
//			hours = ouresttime / 3600;
//			mins =  (ouresttime % 3600) / 60;
//			secs =  (ouresttime % 3600) % 60;
//			strText.Format(_T("%01d:%02d:%02d"), hours, mins, secs);
//			m_timeLeft.SetWindowText(strText);
//			return;
//		}
//	}
//	if (remainingTime > 0)
//	{
//		hours = remainingTime / 3600;
//		mins =  ((int)remainingTime % 3600) / 60;
//		secs =  ((int)remainingTime % 3600) % 60;
//		strText.Format(_T("%01d:%02d:%02d"), hours, mins, secs);
//	}
//	else
//		strText = _T("0:00:00");
//	m_timeLeft.SetWindowText(strText);
}

#include <time.h>
void CBurnCDDlg::UpdateBuffer(LONG usedSystemBuffer, LONG totalSystemBuffer)
{
	CString text;
	CString percent;
	if (usedSystemBuffer && totalSystemBuffer)
	{
		m_bufferCtrl.SetRange32(0, totalSystemBuffer);
		m_bufferCtrl.SetPos(usedSystemBuffer);
		text.Format(_T("Buffer: %d%%"), (100*usedSystemBuffer) / totalSystemBuffer);
	}
	else
	{
		text = _T("Buffer Empty");
		m_bufferCtrl.SetPos(0);
	}
//	int nPercent = usedSystemBuffer / (totalSystemBuffer / 100);
//	percent.Format("%d%%", nPercent);
//	m_BuffPercent.SetWindowText(percent);
	m_bufferText.SetWindowText(text);
	BufferVector.push_back(100 * usedSystemBuffer / totalSystemBuffer);
	BufferVector.push_back(100 * usedSystemBuffer / totalSystemBuffer);
	//BufferVector.push_back(100 * usedSystemBuffer / totalSystemBuffer);
	//BufferVector.push_back(100 * usedSystemBuffer / totalSystemBuffer);
	//BufferVector.push_back(100 * usedSystemBuffer / totalSystemBuffer);
	end = clock();
	cpu_time_used = (float) ( (end - start) / CLOCKS_PER_SEC);
	CPUVector.push_back(cpu_time_used);	
	CPUVector.push_back(cpu_time_used);	
	//CPUVector.push_back(cpu_time_used);	
	//CPUVector.push_back(cpu_time_used);	
	//CPUVector.push_back(cpu_time_used);	
	start = clock();
}

void CBurnCDDlg::UpdateAudioBuffer(LONG usedSystemBuffer, LONG totalSystemBuffer)
{
	CString text;
	CString percent;
	if (usedSystemBuffer && totalSystemBuffer)
	{
		m_bufferCtrl.SetRange32(0, totalSystemBuffer);
		m_bufferCtrl.SetPos(usedSystemBuffer);
		text.Format(_T("Buffer: %d%%"), (100*usedSystemBuffer) / totalSystemBuffer);
	}
	else
	{
		if (m_nCurrentMode == AUDIOCD_DISC)
		{
			m_bufferCtrl.SetPos(totalSystemBuffer);
			text.Format(_T("Buffer: %d%%"), 100);	
		}
		else
		{
			text = _T("Buffer Empty");
			m_bufferCtrl.SetPos(0);
		}
	}
	m_bufferText.SetWindowText(text);
}

void CBurnCDDlg::UpdateAudioProgress(ULONG writtenSectors, ULONG totalSectors, ULONG currentTrack)
{
	bool timeok = false;
	static LONG prevTotalSector = 0;
	CString text, texttrack;
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	//static double lastspeed = 0;
	//double speed = lastspeed;
	double speed = 0;
	COleDateTime time = COleDateTime::GetCurrentTime(); //   
	if (m_start == false)
	{
		m_start = true;
		m_BurnStartTime = time; 
		m_BurnLastTime = time;
		m_ElapsedStartTime  = time;
		m_LastWrittenSectors = 0;
		m_divisor = GetSpeedDivisor((LONG)m_CurrentMediaBurning); // returns bitrate in KBps  (note these are calcuated with 1000 not 1024 per K)
	}
	if (m_LastWrittenSectors > (LONG)writtenSectors)
		m_LastWrittenSectors = 0;
	if (totalSectors && m_datasectors == 0)
		m_datasectors = totalSectors;
	if (totalSectors && (totalSectors != prevTotalSector))
	{
		prevTotalSector = totalSectors;
		m_progressCtrl.SetRange32(0, m_TotalAudioTracks*100);
		m_ProgressTrack.SetRange(0, 100);
	}
	
	if (writtenSectors && totalSectors)
	{
		if (currentTrack == m_TotalAudioTracks && (100*writtenSectors) / totalSectors >= 99)
		{
			text = "Closing disc please wait...";
			texttrack = "";
		}
		else
		{
			int percent = (100*writtenSectors) / totalSectors;
			if (percent == 99)
				percent = 100;
			if (m_TotalAudioTracks && currentTrack)
				texttrack.Format(_T("Track %d of %d is %d%% complete"), currentTrack, m_TotalAudioTracks, percent);
			else
			{
				percent = 100;
				texttrack.Format(_T("Track %d of %d is %d%% complete"), currentTrack, m_TotalAudioTracks, percent);
			}
			m_ProgressTrack.SetPos(percent);
			int Tpercent = ((currentTrack -1 ) * 100) +  percent;
			m_progressCtrl.SetPos(Tpercent);
			if ( pThis->m_pTaskbarList )
				pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, Tpercent, m_TotalAudioTracks*100);

			double totalincrement = 100.0/(float)m_TotalAudioTracks;
			double totalvalue = 0;
			double trackincrement = (float)percent/100.0;
			//percent =((percent+(100/(currentTrack-1))) / m_TotalAudioTracks) * currentTrack;
			//percent =((100/m_TotalAudioTracks) * currentTrack-1) + ((percent/100) * (100/m_TotalAudioTracks));
			if (percent == 50)
			{
				int z = 0;
			}
			if (writtenSectors && totalSectors)
			{
				COleDateTimeSpan tl = time - m_BurnLastTime;
				ULONG lapsedsecs = (((tl.GetHours() * 60) + tl.GetMinutes()) * 60) + tl.GetSeconds();
				if (lapsedsecs >= 2)
				{
					double KBps = ((double)(writtenSectors-m_LastWrittenSectors)* 2);
					double speed = KBps / (m_divisor);
					totalvalue = (totalincrement * (currentTrack-1)) + (trackincrement * totalincrement);
					text.Format(_T("Overall Progress: %d%%  - Speed %u KBps (%4.1fx)  %01d:%02d:%02d"), (int)totalvalue, (UINT)(KBps/(ULONG)lapsedsecs), (float)((KBps / (m_divisor)/lapsedsecs)), m_ElapsedTime.GetHours(), m_ElapsedTime.GetMinutes(), m_ElapsedTime.GetSeconds());
					timeok = true;
					//SpeedVector.push_back((float)((KBps / (m_divisor)/lapsedsecs)));
					//SectorVector.push_back(writtenSectors);;
					//RateVector.push_back((long)tl.m_span);
					m_progressText.SetWindowText(text);
				}
			}
		}
	}
	if (timeok)
	{
		m_LastWrittenSectors = writtenSectors;
		m_BurnLastTime = time;
	}
	m_progressTrackText.SetWindowText(texttrack);
	
}


void CBurnCDDlg::UpdateProgress(ULONG writtenSectors, ULONG totalSectors)
{
	bool timeok = false;
	static LONG prevTotalSector = 0;
	if ( pThis->m_pTaskbarList )
	{
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	}
	COleDateTime time = COleDateTime::GetCurrentTime(); //   
	if (m_start == false)
	{
		m_start = true;
		m_BurnStartTime = time; 
		m_BurnLastTime = time;
		m_ElapsedStartTime  = time;
		m_LastWrittenSectors = 0;
		m_divisor = GetSpeedDivisor((LONG)m_CurrentMediaBurning); // returns bitrate in KBps  (note these are calcuated with 1000 not 1024 per K)
	}
	if (totalSectors && m_datasectors == 0)
		m_datasectors = totalSectors;
	if (totalSectors && (totalSectors != prevTotalSector))
	{
		prevTotalSector = totalSectors;
		m_progressCtrl.SetRange32(0, totalSectors);
		m_progressCtrl.SetPos(0);
	}
	m_progressCtrl.SetRange32(0, totalSectors);
	m_progressCtrl.SetPos(writtenSectors);
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, writtenSectors, totalSectors);

	if (writtenSectors && totalSectors)
	{
		COleDateTimeSpan tl = time - m_BurnLastTime;
		ULONG lapsedsecs = (((tl.GetHours() * 60) + tl.GetMinutes()) * 60) + tl.GetSeconds();
		if (lapsedsecs >= 2)
		{
			//else if (lapsedsecs == 0)
			//lapsedsecs = 1;
			double KBps = ((double)(writtenSectors-m_LastWrittenSectors)* 2);
			double speed = KBps / (m_divisor);
			m_Progresstext.Format(_T("Progress: %d%% - Speed %u KBps (%4.1fx) %01d:%02d:%02d"), (100*writtenSectors)/totalSectors, (UINT)(KBps/(ULONG)lapsedsecs), (float)((KBps / (m_divisor)/lapsedsecs)), m_ElapsedTime.GetHours(), m_ElapsedTime.GetMinutes(), m_ElapsedTime.GetSeconds());
			CString text1;
//			text1.Format(_T("Progress: %d%% - Speed %u KBps (%4.1fx)"), (100*writtenSectors)/totalSectors, (UINT)(KBps/lapsedsecs), speed/lapsedsecs);
//			SAFE_LOG(out, text1, true);
//			text1.Format(_T("burn time %d "), (LONG)m_BurnStartTime);
//			SAFE_LOG(out, text1, false);
//			text1.Format(_T("Secs %d "), (LONG)lapsedsecs);
//			SAFE_LOG(out, text1, false);
//			text1.Format(_T("Time %d"), (LONG)time);
//			SAFE_LOG(out, text1, true);
			timeok = true;
			SpeedVector.push_back((float)((KBps / (m_divisor)/lapsedsecs)));
			//SpeedVector.push_back((float)((KBps / (m_divisor)/lapsedsecs)));
			SectorVector.push_back(writtenSectors);;
			//SectorVector.push_back(writtenSectors);;
			RateVector.push_back((long)tl.m_span);
			//RateVector.push_back((long)tl.m_span);
		}
		
	}
	else
	{
		m_Progresstext = _T("Progress");
	}
	m_progressText.SetWindowText(m_Progresstext);
	if (timeok)
	{
		m_LastWrittenSectors = writtenSectors;
		m_BurnLastTime = time;
	}
}

void CBurnCDDlg::UpdateEraseProgress(ULONG total, ULONG remaining)
{
	CString text;
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	ULONG elapsed = total - remaining;
	int percent = elapsed * 100 / total;
	if (percent > 100)
		percent = 100;
	m_progressCtrl.SetPos(percent);
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, percent, 100);

	if (total && remaining)
	{
		text.Format(_T("Progress: %d%%"), percent);
	}
	//else
	//{
	//    text = _T("Progress");
	//	m_progressCtrl.SetPos(0);
	//}
	m_progressText.SetWindowText(text);
}

void CBurnCDDlg::UpdateVerifyProgress(ULONG writtenSectors, ULONG totalSectors)
{
	static LONG prevTotalSector = 0;
	CString text;
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	COleDateTime time = COleDateTime::GetCurrentTime(); //.GetHour() * 60) + (COleDateTime::GetCurrentTime().GetMinute() * 60)) + COleDateTime::GetCurrentTime().GetSecond();
	if (m_start == false)
	{
		m_start = true;
		m_BurnStartTime = time;
		m_divisor = GetSpeedDivisor((LONG)m_CurrentMediaBurning);  // returns bitrate in KBps  (note these are calcuated with 1000 not 1024 per K)
	}
//	if (time > m_BurnStartTime)
//	{
		
//	}
	if (totalSectors && (totalSectors != prevTotalSector))
	{
		prevTotalSector = totalSectors;
		m_progressCtrl.SetRange32(0, totalSectors);
	}
	m_progressCtrl.SetPos(writtenSectors);
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, writtenSectors, totalSectors);


	if (writtenSectors && totalSectors)
	{
		COleDateTimeSpan tl = time - m_BurnStartTime;
		ULONG lapsedsecs = (((tl.GetHours() * 60) + tl.GetMinutes()) * 60) + tl.GetSeconds();
		if (lapsedsecs == 0)
			lapsedsecs = 1;
		double KBps = ((double)writtenSectors * 2.048);
		double speed = KBps / m_divisor;	
		text.Format(_T("Verify Progress: %d%% - Speed %u KBps (%4.1fx) %01d:%02d:%02d"), (100*writtenSectors)/totalSectors, (UINT)(KBps/lapsedsecs), speed/(ULONG)lapsedsecs, m_ElapsedTime.GetHours(), m_ElapsedTime.GetMinutes(), m_ElapsedTime.GetSeconds());
		//double KBps = ((((double)writtenSectors*2048.0)/lapsedsecs) / 1000.0)+5; // sectors of course are 2048 bytes.
		//LONG KBps = (((writtenSectors*2048)/lapsedsecs) / 1000)+1; // sectors of course are 2048 bytes.
		//double speed = KBps / divisor;  //Total KBps written so far,  divided by a 1.0x bitrate in KBps
		//text.Format(_T("Verify Progress: %d%% - Speed %d KBps (%4.1fx)"), (100*writtenSectors) / totalSectors, (int)KBps, speed);
	}
	else
	{
		text = _T("Progress");
	}
	//lastspeed = speed;
	m_progressText.SetWindowText(text);
}

void CBurnCDDlg::UpdateVerifyTimes(LONG totalTime, LONG remainingTime, ULONG writtenSectors, ULONG totalSectors)
{
	m_ElapsedTime = GetCurrentTime() - m_BurnLastTime;
	// Set the estimated total time
//	CString strText;
//	int hours, mins, secs;
//	hours = totalTime / 3600;
//	mins =  (totalTime % 3600) / 60;
//	secs =  (totalTime % 3600) % 60;
//	if (totalTime > 0)
//		strText.Format(_T("%01d:%02d:%02d"),  hours, mins, secs);
//	else
//		strText = _T("0:00:00");
//	//m_estimatedTime.SetWindowText(strText);
//	// Set the estimated remaining time
//	if (writtenSectors && totalSectors && remainingTime == 0)
//	{
//		int percent = (100*writtenSectors) / totalSectors;
//		if (percent == 99)
//			percent = 100;
//		if (percent)
//		{
//			LONG ouresttime = (totalTime * (100/percent)) - totalTime;
//			hours = ouresttime / 3600;
//			mins =  (ouresttime % 3600) / 60;
//			secs =  (ouresttime % 3600) % 60;
//			strText.Format(_T("%01d:%02d:%02d"),hours, mins, secs);
//			//m_timeLeft.SetWindowText(strText);
//			return;
//		}
//	}
//	if (remainingTime > 0)
//	{
//		hours = remainingTime / 3600;
//		mins =  (remainingTime % 3600) / 60;
//		secs =  (remainingTime % 3600) % 60;
//		strText.Format(_T("%01d:%02d:%02d"),hours, mins, secs);
//	}
//	else
//		strText = _T("0:00:00");
//	//m_timeLeft.SetWindowText(strText);
}

//void CBurnCDDlg::OnCbnSelchangeMediaTypeCombo()
//{
//    //int selectedIndex = m_mediaTypeCombo.GetCurSel();
//    //if (selectedIndex == -1)
//    //{
//    //   m_selectedMediaType = -1;
//    //}
//    //else
//    //{
//    //    m_selectedMediaType = (int)m_mediaTypeCombo.GetItemData(selectedIndex);
//    //}
//	//
//    //UpdateCapacity();
//}

void CBurnCDDlg::UpdateCapacity(BOOL bQuiet)
{
	int response = -1;
	if (m_BurnButtonClicked == 1)
		return;
	SetWaitCursor(TRUE);
	ULONGLONG mediaSize = 0;
	BOOL isAudio = FALSE;
	m_hasWav = FALSE;
	CString TotalText, filename, ext;
	//m_TotalSizeText.SetWindowText("Getting Size");
	ULONGLONG filesize;
	int itemCount = m_fileListbox.GetCount();
	for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
	{
		CBaseObject* pObject = (CBaseObject*)m_fileListbox.GetItemDataPtr(itemIndex);
		filesize = pObject->GetSizeOnDisc();
		filename = pObject->GetName();
		if (itemIndex == 0)
		{
			CString tmp = pObject->GetPath();
			GetParentFolderName(&tmp);
			if (m_volumelabelchanged == FALSE)
				m_volumeLabel = tmp;
		}
		ext = filename.Right(3);
		ext.MakeLower();
		if (ext == "wav")
		{
			isAudio = TRUE;
			m_hasWav = TRUE;
		}
		else if (ext == "mp3")
			isAudio = TRUE;
		else
			isAudio = FALSE;
		if (m_FileSystemCombo.GetCurSel() == FS_AUDIOCD || m_FileSystemCombo.GetCurSel() == FS_AUDIOCD_DAO)
		{
			if (ext == "m4a")
			{
				MessageBox("M4A files are not yet supported.  Use iTunes to convert them to MP3 format first");
					return;
			}
		}
		if (filesize >= 0x80000000 && m_RadioBurnFilesFolders == 0 && pObject->IsKindOf(RUNTIME_CLASS(CFileObject))) //2GB or more needs UDF
		{
			//MessageBox(filename);
			if ( m_FileSystemCombo.GetCurSel() == FS_ISO9660 || m_FileSystemCombo.GetCurSel() == FS_ISO9660_JOLIET)
			{
				if (m_FileSystemCombo.GetCurSel() == FS_AUTO)
				{
					m_nAutoFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet;
					GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE); //enable the UDF revision option
					m_UDFRevision.SetCurSel(UDF_AUTO);
					m_AutoUDFVersion = 0x102;
					SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("ISO9660 + Joliet FS Auto selected"));
					UpdateData(FALSE);	
				}
				else
				{
					if(MessageBox("There is a file larger than 2GB which requires UDF FileSystem.  Do you want me to set this FileSystem for you?", "UDF Required", MB_ICONQUESTION|MB_YESNO) == IDYES)
					{
						m_nAutoFileSystem = /*FsiFileSystemISO9660|FsiFileSystemJoliet|*/FsiFileSystemUDF;
						GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE); //enable the UDF revision option
						m_UDFRevision.SetCurSel(UDF_AUTO);
						m_FileSystemCombo.SetCurSel(/*FS_ISO9660_JOLIET_UDF*/FS_UDF);
						m_AutoUDFVersion = 0x102;
						UpdateData(FALSE);
					}
				}
			}
		}
		mediaSize += filesize;
		CString cName = pObject->GetName();
		cName.MakeUpper();
		if (cName == "VIDEO_TS" && m_FileSystemCombo.GetCurSel() == FS_AUTO)
		{
			CString tmp = pObject->GetPath();
			GetParentFolderName(&tmp);
			if (m_volumelabelchanged == FALSE)
				m_volumeLabel = tmp;
			m_nAutoFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet|FsiFileSystemUDF;
			m_AutoUDFVersion = 0x102;
			m_UDFRevision.SetCurSel(UDF_102);
			m_FileSystemCombo.SetCurSel(FS_ISO9660_JOLIET_UDF);
			SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("DVD-Video File System selected"));
			UpdateData(FALSE);
		}
		else if (cName == "BDMV" && m_FileSystemCombo.GetCurSel() == FS_AUTO)
		{
			CString tmp = pObject->GetPath();
			GetParentFolderName(&tmp);
			if (m_volumelabelchanged == FALSE)
				m_volumeLabel = tmp;
			m_nAutoFileSystem = FsiFileSystemUDF;
			m_AutoUDFVersion = 0x250;
			m_FileSystemCombo.SetCurSel(FS_UDF);
			m_UDFRevision.SetCurSel(UDF_250);
			SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Blu-ray File System Auto selected"));
			UpdateData(FALSE);
		}
		else if (response == -1 && isAudio && (m_FileSystemCombo.GetCurSel() != FS_AUDIOCD && m_FileSystemCombo.GetCurSel() != FS_AUDIOCD_DAO))
		{
			CMessageClassDlg dlg;
			{
				if (bQuiet == FALSE)
				{
					dlg.SetIconQuestionMark();
					dlg.SetTitleText("What type of disc would you like?");
					dlg.EnableOKButton(TRUE);
					dlg.SetText("Your list contains all music files,  do you want to burn a Music CD or a Music Data Disc?");
					dlg.SetLeftText("Music CD");
					dlg.SetRightText("Cancel");
					dlg.SetMiddleText("Data Disc");
					dlg.SetDoNotShow(FALSE);
					response = (UINT)dlg.DoModal();
					if (response == 0)
						response = 2;
					if ( response == CMessageClassDlg::LEFTBTN)//Audio CD Response
					{
						DWORD SectorsPerCluster=0;     // sectors per cluster
						DWORD BytesPerSector=0;        // bytes per sector
						DWORD NumberOfFreeClusters=0;  // free clusters
						DWORD TotalNumberOfClusters=0; // total clusters
						CString drive;
						GetTempPath( MAX_PATH, drive.GetBuffer(MAX_PATH));
						GetDiskFreeSpace(drive, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
						float bytes = (float)(SectorsPerCluster * NumberOfFreeClusters)* BytesPerSector;
						if ((bytes/1024)/1024 < 800)
						{
							m_nAutoFileSystem = FSi_AUDIOCD;
							m_FileSystemCombo.SetCurSel(FS_AUDIOCD);
						}
						else
						{
							m_nAutoFileSystem = FSi_AUDIOCD_DAO;
							m_FileSystemCombo.SetCurSel(FS_AUDIOCD_DAO);
						}				
						//GetDlgItem(IDC_STATICUDFREV)->EnableWindow(FALSE);
						//GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(FALSE);
						//GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(FALSE);
						//GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(FALSE);
						//GetDlgItem(IDC_RADIOBURNISO)->EnableWindow(FALSE);
						//GetDlgItem(IDC_CHECK_BOOTIMAGE)->EnableWindow(FALSE);
						UpdateData(FALSE);
					}
					else if ( response == CMessageClassDlg::RIGHTBTN)//Data CD Response
					{
						m_nAutoFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet;
						//GetDlgItem(IDC_STATICUDFREV)->EnableWindow(FALSE);
						//GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(FALSE);
						//GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(FALSE);
						//GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(TRUE);
						//GetDlgItem(IDC_RADIOBURNISO)->EnableWindow(FALSE);
						//GetDlgItem(IDC_CHECK_BOOTIMAGE)->EnableWindow(FALSE);
						m_FileSystemCombo.SetCurSel(FS_ISO9660_JOLIET_UDF);
						UpdateData(FALSE);
					}
				}
			}
		}
	}
	if (mediaSize < 1024*1024)
		TotalText.Format("%4.2fKB", (float)mediaSize/1024);
	else if (mediaSize < 1024*1024*1024)
		TotalText.Format("%4.2fMB",(float)mediaSize/1048576);
	else
		TotalText.Format("%4.2fGB",(float)mediaSize/1073741824);
	m_TotalSizeText.SetWindowText(TotalText);
	
	if (m_TotalSectorsOnMedia == 0)
	{
		 SetWaitCursor(FALSE);
		return;
	}
	ULONGLONG bytevalue =(ULONGLONG) ((double)m_TotalSectorsOnMedia)*2048;
	
	// Set the selected media type data
	ULONGLONG totalSize = 0;
	CString maxText = "0";
	if (m_selectedMediaType == CD_MEDIA)
	{
		maxText.Format("%4.2fMB", (float)m_TotalSectorsOnMedia/512);
		totalSize = bytevalue;
	}
	else if (m_selectedMediaType == DVD_MEDIA)
	{
		maxText.Format("%4.2fGB",(float)m_TotalSectorsOnMedia/524288);
		totalSize = bytevalue;
	}
	else if (m_selectedMediaType == DL_DVD_MEDIA)
	{
		maxText.Format("%4.2fGB",(float)m_TotalSectorsOnMedia/524288);
		totalSize = bytevalue;
	}
	else if (m_selectedMediaType == BD_MEDIA || m_selectedMediaType == DL_BD_MEDIA)
	{
	   maxText.Format("%4.2fGB",(float)m_TotalSectorsOnMedia/524288);
	   totalSize = bytevalue;
	}
	m_maxText.SetWindowText(maxText);
	
	m_capacityProgress.SetRange(0,100);
	if (mediaSize == 0)
	{
		m_capacityProgress.SetPos(0);
//#if _MFC_VER >= 0x0900
//        m_capacityProgress.SetState(PBST_NORMAL);
//#endif
	}
	else 
	{
		if (totalSize>0)
		{
			int percent = (int)((mediaSize*100)/totalSize);
			if (percent > 100 && mediaSize > 0 && m_oversizequestion == false)
			{
				m_oversizequestion = true;
				SetWaitCursor(FALSE);
				m_capacityProgress.SetPos(100);
				if (MessageBox("Total file size is greater than the current media can hold.  Do you want to continue?", "Total Data too big", MB_ICONQUESTION|MB_YESNO) == IDNO)
					return;           
//#if _MFC_VER >= 0x0900
//            m_capacityProgress.SetState(PBST_ERROR);
//#endif
			}
			else
			{
			 m_capacityProgress.SetPos(percent);
//#if _MFC_VER >= 0x0900
//            m_capacityProgress.SetState(PBST_NORMAL);
//#endif
			}
		}
		m_TotalSizeToBurn = mediaSize; //used to give progress on adding files to filesystem
		m_TotalSizeFree = totalSize;
	}
	
	SetWaitCursor(FALSE);
}

void CBurnCDDlg::GetParentFolderName(CString *filename)
{
	CString tmp;
	int idx = filename->ReverseFind(_T('\\'));
	tmp = filename->Left(idx);
	idx = tmp.ReverseFind(_T('\\'));
	*filename = tmp.Mid(idx+1);		
}

void CBurnCDDlg::EnableBurnButton()
{
	if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())   //Hard disk selected
	{
		GetDlgItem(IDC_BURN_BUTTON)->EnableWindow(m_fileListbox.GetCount()>0);
		return;
	}
	if (isMediaLoaded())												//is there a disc in the drive?
	{
		GetDlgItem(IDC_BURN_BUTTON)->EnableWindow(m_fileListbox.GetCount()>0);
		//m_MediaSpeeds.EnableWindow(m_fileListbox.GetCount()>0);
	}
	else
	{
		GetDlgItem(IDC_BURN_BUTTON)->EnableWindow(FALSE);
		//m_MediaSpeeds.EnableWindow(FALSE);
	}
	if (isMediaLoaded() && isMediaBlank() == 0 && m_RadioBurnFilesFolders == 1)
		GetDlgItem(IDC_ISODISC)->EnableWindow(TRUE);
	else
		GetDlgItem(IDC_ISODISC)->EnableWindow(FALSE);
}

void CBurnCDDlg::OnBnClickedRemoveFilesButton()
{
	int nCount = m_fileListbox.GetSelCount();
	if (nCount == 0)
		return;
	CString message = _T("Are you sure you want to remove these file(s)?");
	if (AfxMessageBox(message, MB_YESNO|MB_ICONQUESTION) == IDNO)
		return;
	CArray<int,int> aryListBoxSel;
	aryListBoxSel.SetSize(nCount);
	m_fileListbox.GetSelItems(nCount, aryListBoxSel.GetData()); 
	//note we delete from the bottom up so the indexes dont get all screwed	
	for (int i=nCount-1; i>=0; i--)
	{
		DeleteItem(aryListBoxSel[i]);
	}
	OnLbnSelchangeBurnFileList();
	EnableBurnButton();
	UpdateCapacity();
}

void CBurnCDDlg::OnClickedButtonRemoveall()
{
	if (m_fileListbox.GetCount() == 0)
		return;
	if (MessageBox("Are you sure you want to remove all items in the list", "Are you sure", MB_ICONQUESTION|MB_YESNO) == IDNO)
		return;
	m_fileListbox.ResetContent();
	OnLbnSelchangeBurnFileList();
	EnableBurnButton();
	UpdateCapacity();
}


void CBurnCDDlg::DeleteItem(int index)
{
	int nCount = m_fileListbox.GetSelCount();
	if (nCount == 0)
		return;
	CBaseObject* pBaseObject = (CBaseObject*)m_fileListbox.GetItemDataPtr(index);
	if (pBaseObject <= 0)
		return;
	m_fileListbox.DeleteString(index); 
	delete pBaseObject;
	
}

void CBurnCDDlg::EnableUI(BOOL bEnable)
{
	if (bEnable)
		SetThreadExecutionState(ES_CONTINUOUS);
	else
		SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
	if (bEnable)
	{
		m_progressCtrl.SetPos(0);
		m_bufferCtrl.SetPos(0);
		m_ProgressTrack.SetPos(0);
		// Clear the taskbar progress bar.
		if ( pThis->m_pTaskbarList )
			pThis->m_pTaskbarList->SetProgressState ( pThis->m_hWnd, TBPF_NOPROGRESS );
	}
	m_deviceComboBox.EnableWindow(bEnable);
	m_fileListbox.EnableWindow(bEnable);
	GetDlgItem(IDC_ADD_FILES_BUTTON)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_REMOVEALL)->EnableWindow(bEnable);
	GetDlgItem(IDC_REMOVE_FILES_BUTTON)->EnableWindow(bEnable);
	GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(bEnable);
	GetDlgItem(IDC_VOLUME)->EnableWindow(bEnable);
	//GetDlgItem(IDC_BURN_BUTTON)->SetWindowText(bEnable ? _T("Burn") : _T("Cancel"));
	//GetDlgItem(IDC_ERASE)->SetWindowText(bEnable ? _T("Erase") : _T("Cancel"));
	bEnable ? m_Burn.SetIcon(m_burn) : m_Burn.SetIcon(m_stop);
	if (bEnable)
	{
		FREETOOL(IDC_BURN_BUTTON));
		ADDTOOL(IDC_BURN_BUTTON),_T("Starts the burning process"));
	}
	else
	{
		FREETOOL(IDC_BURN_BUTTON));
		ADDTOOL(IDC_BURN_BUTTON),_T("Attempts to cancel the burning process"));
	}

	GetDlgItem(IDC_RADIOBURNFILES)->EnableWindow(bEnable);
	GetDlgItem(IDC_RADIOBURNISO)->EnableWindow(bEnable);
	//GetDlgItem(IDC_CHECK_FULLERASE)->EnableWindow(bEnable);	
	GetDlgItem(IDC_BUTTON_EJECT)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_UP)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_DOWN)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_SAVE)->EnableWindow(bEnable);
	GetDlgItem(IDC_BUTTON_LOAD)->EnableWindow(bEnable);
	GetDlgItem(IDC_COMBO_MEDIA_SPEEDS)->EnableWindow(bEnable);
	GetDlgItem(IDC_COMBO_FILESYSTEM)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_BURNPROOF)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_BOOTIMAGE)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_MULTISESSION)->EnableWindow(bEnable);
	GetDlgItem(IDC_STATICFILESYSTEM)->EnableWindow(bEnable);
	GetDlgItem(IDC_STATICSPEED)->EnableWindow(bEnable);
	GetDlgItem(IDC_COMBO_VERIFY)->EnableWindow(bEnable);
	GetDlgItem(IDC_STATIC_VERIFY)->EnableWindow(bEnable);
	GetDlgItem(IDC_HELPBUTTON)->EnableWindow(bEnable);
	GetDlgItem(IDC_ERASE)->EnableWindow(bEnable);
	GetDlgItem(IDC_CHECK_USECAV)->EnableWindow(bEnable);	
	GetDlgItem(IDC_EDIT_NUMCOPIES)->EnableWindow(bEnable);
	GetDlgItem(IDC_SPIN2)->EnableWindow(bEnable);
	GetDlgItem(IDC_STATIC_NUMCOPIES)->EnableWindow(bEnable);

	if (isMediaLoaded() && isMediaBlank() == 0 && bEnable == TRUE && m_RadioBurnFilesFolders == 1)
		GetDlgItem(IDC_ISODISC)->EnableWindow(TRUE);
	else
		GetDlgItem(IDC_ISODISC)->EnableWindow(FALSE);
	if (bEnable == FALSE)
	{
		GetDlgItem(IDC_STATICUDFREV)->EnableWindow(bEnable);
		GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(bEnable);
	}
	else
		OnSelchangeComboFilesystem();
	ChangeDeviceCombo();
	if (m_nCurrentMode != PROGRAM_IDLE)
	{
		GetDlgItem(IDC_ERASE)->EnableWindow(FALSE);
	}
	if (SpeedVector.size() > 0)
		m_SaveIBG.EnableWindow(TRUE);
	else
		m_SaveIBG.EnableWindow(FALSE);
	EnableBurnButton();
}

void CBurnCDDlg::SetCancelAudioBurning(bool bCancel)
{
	CSingleLock singleLock(&m_critSection);
	m_cancelaudioBurn = bCancel;
}

bool CBurnCDDlg::GetCancelAudioBurning()
{
	CSingleLock singleLock(&m_critSection);
	return m_cancelaudioBurn;
}

void CBurnCDDlg::SetCancelBurning(bool bCancel)
{
	CSingleLock singleLock(&m_critSection);
	m_cancelBurn = bCancel;
}

bool CBurnCDDlg::GetCancelBurning()
{
	CSingleLock singleLock(&m_critSection);
	return m_cancelBurn;
}

void CBurnCDDlg::SetCancelErasing(bool bCancel)
{
	CSingleLock singleLock(&m_critSection);
	m_cancelErase = bCancel;
}

void CBurnCDDlg::SetCancelISOFromDisc(bool bCancel)
{
	m_cancelISOFromDisc = bCancel;
}

bool CBurnCDDlg::GetCancelErasing()
{
	CSingleLock singleLock(&m_critSection);
	return m_cancelErase;
}

#include <sys\types.h> 
#include <sys\stat.h>
__int64 CBurnCDDlg::FileSize64( CString* szFileName ) 
{ 
  struct _stati64 fileStat; 
  int err = _stati64( (const char*)szFileName->GetBuffer(0), &fileStat ); 
  if (0 != err) return 0; 
  return fileStat.st_size; 
}

//Added by Nic  Burn routine for writing ISO files
UINT CBurnCDDlg::WriteISOThread(LPVOID pParam)
{
	CBurnCDDlg* pThis = (CBurnCDDlg*)pParam;
	// Get the selected recording device from the combobox
	int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	ASSERT(selectedIndex >= 0);
	if (selectedIndex < 0)
	{
		pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Error: No device selected"));
		return 0;
	}
	CDiscRecorder* pOrigDiscRecorder = 
		(CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (pOrigDiscRecorder == NULL)
	{
		// This should never happen
		pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Error: pOrigDiscRecorder is NULL"));
		return 0;
	}
	// Did user cancel?
	if (pThis->GetCancelBurning())
	{
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Write ISO cancelled"));
		return 0;
	}
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Preparing burner..."));
	// Create another disc recorder because we're in a different thread
	CDiscRecorder discRecorder;
	CString errorMessage;
	if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
	{
		if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
		{
			CDiscFormatData discFormatData;
			if (discFormatData.Initialize(&discRecorder, CLIENT_NAME))
			{
				// Get the media type currently in the recording device
				IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
				discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
				IStream* dataStream = NULL;
				CString file = pThis->ISOfile;
				HRESULT hRes = SHCreateStreamOnFile(file.GetBuffer(0), STGM_SHARE_DENY_WRITE, &dataStream);
				discFormatData.SetCloseMedia(pThis->m_closeMedia.GetCheck() ? true : false);
				// Write the ISO
				discFormatData.Burn(pThis->m_hWnd, dataStream);
				// Release the IStream after burning
				dataStream->Release();
				// Eject Media if they chose
				CString num;
				pThis->m_NumberofCopies.GetWindowTextA(num.GetBuffer(10), 10);
				num.ReleaseBuffer();
				if (atoi(num) > 1)// || pThis->m_nNumberofCopies > 1
				{
					discRecorder.EjectMedia();
					if (pThis->m_nNumberofCopies > 1)
					{
						pThis->DoNextCopy();
						discRecorder.ReleaseExclusiveAccess();
						return 0;
					}
				}
				if (pThis->m_ejectWhenFinished.GetCheck())
				{
					discRecorder.EjectMedia();	
				}
			}
			discRecorder.ReleaseExclusiveAccess();
			// Finished Burning, GetHresult will determine if it was successful or not
			pThis->SendMessage(WM_BURN_FINISHED, discFormatData.GetHresult(), (LPARAM)(LPCTSTR)discFormatData.GetErrorMessage());
		}
		else
		{
			errorMessage.Format(_T("Failed: %s is exclusive owner"), (LPCTSTR)discRecorder.ExclusiveAccessOwner());
			pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
		}
	}
	else
	{
		errorMessage.Format(_T("Failed to prepare burner - Unique ID:%s"), (LPCTSTR)pOrigDiscRecorder->GetUniqueId());
		pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
	}
	return 0;
}

void CBurnCDDlg::FormatNumber1024(double bytes, LPTSTR buffer, int bufsize)
{
	_TCHAR DivStr[2] = {0,0};
	double divided = bytes;
	DivStr[0] = ' ';
	if (divided >= 1024.0)
	{
		DivStr[0] = 'K';  //Kilobyte
		divided /= 1024.0;
	}
	if (divided >= 1024.0)
	{
		DivStr[0] = 'M';	//Megabyte
		divided /= 1024.0;
	}
	if (divided >= 1024.0)
	{
		DivStr[0] = 'G';	//Gigabyte
		divided /= 1024.0;
	}
	if (divided >= 1024.0)
	{
		DivStr[0] = 'T';	//Terabyte
		divided /= 1024.0;
	}
	if (divided >= 1024.0)
	{
		DivStr[0] = 'P';	//Petabyte
		divided /= 1024.0;
	}
	if (divided >= 1024.0)
	{
		DivStr[0] = 'E';	//Exabyte
		divided /= 1024.0;
	}
	_stprintf_s(buffer, bufsize, _T("%9.2f %sB"),(float)divided, DivStr);
	return;
}

// Write wav files to CD

#include "DiscFormatTrackAtOnce.h"
UINT CBurnCDDlg::AudioDAOThread(LPVOID pParam)
{
	CBurnCDDlg* pThis						= (CBurnCDDlg*)pParam;
	HRESULT hr								= S_OK;
	BOOLEAN bReturn							= TRUE;
	IStream* streamData						= NULL;
		
	CString cWorkingFolder;
	GetTempPath(MAX_PATH, cWorkingFolder.GetBuffer(MAX_PATH));
	cWorkingFolder.ReleaseBuffer();
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	
loop:
	DWORD SectorsPerCluster=0;     // sectors per cluster
	DWORD BytesPerSector=0;        // bytes per sector
	DWORD NumberOfFreeClusters=0;  // free clusters
	DWORD TotalNumberOfClusters=0; // total clusters
	CString drive = cWorkingFolder.Left(2);
	GetDiskFreeSpace(drive, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
	float bytes = (float)(SectorsPerCluster * NumberOfFreeClusters)* BytesPerSector;
	CString mediasize;
	pThis->m_TotalSizeText.GetWindowText(mediasize);
	float multiplier = 1; //default to MB
	if (mediasize.GetAt(mediasize.GetLength()-2) == 'G')
		multiplier = 1024;
	else if (mediasize.GetAt(mediasize.GetLength()-2) == 'K')
		multiplier = (float)0.1;
	mediasize.SetAt(mediasize.GetLength()-2, 0);
	int size = (int) (atoi(mediasize.GetBuffer(0)) * multiplier);
	if ((bytes/1024)/1024 < size)
	{
		CString tmpstr;
		tmpstr.Format("Drive %s does not have enough free space (700MB).  Do you want to supply a new drive/folder to use for temporary space?", drive);
		if (pThis->MessageBox(tmpstr, "Not enough free space", MB_ICONQUESTION|MB_YESNO) == IDNO)
		{
			pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"Not enough free space");
			return -1;
		}
		BROWSEINFO bi = {0};
		bi.hwndOwner = pThis->m_hWnd;
		bi.ulFlags = BIF_NONEWFOLDERBUTTON |BIF_RETURNONLYFSDIRS;
		LPITEMIDLIST lpidl = SHBrowseForFolder(&bi);
		if (!lpidl)
		{
			pThis->SendMessage(WM_BURN_FINISHED,-3, (LPARAM)(LPCTSTR)"SHBrowseForFolder failed");
			return -1;
		}
		TCHAR selectedPath[_MAX_PATH] = {0};
		if (SHGetPathFromIDList(lpidl, selectedPath))
		{
			CDirObject* pDirObject = new CDirObject(selectedPath);
			cWorkingFolder = pDirObject->GetName();
		}
		goto loop;
	}
	size = pThis->m_capacityProgress.GetPos();
	if (pThis->m_hasWav == FALSE)
	{
		if (((pThis->m_TotalSizeToBurn/100)*size) * 10 > pThis->m_TotalSizeToBurn)
		{
			CString tmpstr;
			tmpstr.Format("The un-compressed size of the music may not fit on the disc.  Do you want to try anyway?", drive);
			if (pThis->MessageBox(tmpstr, "Music may not fit", MB_ICONQUESTION|MB_YESNO) == IDNO)
			{
				pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"Cancelled as requested");
				return -1;
			}
		}
	}
	IRawCDImageCreator* raw = NULL;
	hr = pThis->GetCDImageCreatorInterface(&raw);

	ULONG selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		pThis->m_progressTrackText.EnableWindow(FALSE);
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"No drive selected");
		return -1;
	}
	CDiscFormatRawCD discFormatRawCD;
	IDiscFormat2RawCD *pDiscFormatRawCD;
	CDiscRecorder* pOrigDiscRecorder = (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	CString *carray = NULL;
	// Create another disc recorder because we're in a different thread
	CDiscRecorder discRecorder;
	if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
	{
		if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
		{
			discFormatRawCD.pThis = pThis;
			if (!discFormatRawCD.Initialize(&discRecorder, CLIENT_NAME) != NULL)
			{
				pThis->m_progressTrackText.EnableWindow(FALSE);
				pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"discFormatRawCD.Initialize Failed");
				return -1;
			}
			pDiscFormatRawCD = discFormatRawCD.GetIDiscFormatRawCDPtr();
			// set the image type
			hr = raw->put_ResultingImageType(IMAPI_FORMAT2_RAW_CD_SUBCODE_IS_RAW); //IMAPI_FORMAT2_RAW_CD_SUBCODE_PQ_ONLY);
			if (FAILED(hr))
			{
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed put_ResultingImageType"));
				raw->Release();
				return -1;
			}
			pThis->m_nCurrentMode = AUDIOCD_DISC;
			// Add all the tracks from the list control
			LONG index = 0;
			carray = new CString[pThis->m_fileListbox.GetCount()];
			if (SUCCEEDED(hr))
			{
				CString tmpstr;
				CBaseObject* pObject;
				pThis->m_TotalAudioTracks = 0;
				pThis->m_progressCtrl.SetRange(0, pThis->m_fileListbox.GetCount());
				pThis->m_ProgressTrack.SetRange(0, pThis->m_fileListbox.GetCount());
				pThis->m_progressCtrl.SetPos(0);
				pThis->m_ProgressTrack.SetPos(0);
				// Clear the taskbar progress bar.
				if ( pThis->m_pTaskbarList )
					pThis->m_pTaskbarList->SetProgressState ( pThis->m_hWnd, TBPF_NOPROGRESS );
				pThis->m_TotalAudioTracks = pThis->m_fileListbox.GetCount();
				double totalimagesize = 0;
				for (int i=0; i < pThis->m_fileListbox.GetCount(); i++)
				{
					pObject = (CBaseObject*)pThis->m_fileListbox.GetItemDataPtr(i);
					ASSERT(pObject != NULL);
					if (pObject == NULL)
					{
						pThis->m_TotalAudioTracks--;
						continue;
					}
					CString fileName = pObject->GetPath();			
					if (pThis->isDirectory(fileName.GetBuffer(0)))
					{
						//folders are not allowed
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Skipping folder item in the list"));
						pThis->m_TotalAudioTracks--;
						continue;		
					} 
					// We have a file, let's add it
					IStream * testStream = NULL;
					STATSTG stat;			
					CString temp, path, outfile;
					temp = fileName.Right(3);
					temp.MakeLower();
					if (temp == "mp3")
					{
						CString str;
						str.Format(_T("Converting %s"), pObject->GetName());
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str.GetBuffer(0));
						//GetTempPath(MAX_PATH, temp.GetBuffer(MAX_PATH));
						//temp.ReleaseBuffer();
						path = cWorkingFolder;
						int idx = fileName.ReverseFind(_T('\\'));
						temp = fileName.Mid(idx+1);
						temp = temp.Left(temp.GetLength()-3);
						outfile.Format("%s%s%s", path, temp, "wav");
						int stat = pThis->ConvertMP3toWAV(&fileName,  &outfile);
						if (stat != 0)
						{
							pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Error converting mp3"));
							pThis->m_TotalAudioTracks--;
							continue;
						}
						fileName = outfile;
						carray[i] = fileName;
					}
					else if (temp != "wav")
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Skipping invalid file"));
						pThis->m_TotalAudioTracks--;
						continue;
					}
					totalimagesize += pThis->FileSize64(&fileName); 
					if (pThis->m_TotalSizeFree>0)
					{
						int percent = (int)((totalimagesize*100)/pThis->m_TotalSizeFree);
						char buffer[100];
						pThis->FormatNumber1024(totalimagesize, buffer, 100);
						pThis->m_TotalSizeText.SetWindowText(buffer);
						pThis->m_capacityProgress.SetPos(percent);
						if (percent > 100 && size > 0)
						{
							pThis->m_capacityProgress.SetPos(100);
							if (pThis->MessageBox("Total file size is greater than the CD.  Do you want to continue?", "Total Data too big", MB_ICONQUESTION|MB_YESNO) == IDNO)
							{
								pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"Cancelled as requested");
								discFormatRawCD.FreeRecorder();
								discRecorder.ReleaseExclusiveAccess();
								for (int i=0; i< pThis->m_fileListbox.GetCount(); i++)
								{
									if (carray[i] == "")
										break;
									int result = DeleteFile(carray[i]);
								}
								delete [] carray;
								return -1;           
							}		
						}
					}
					LPWSTR lpszW = new WCHAR[255];
					LPTSTR lpStr = fileName.GetBuffer(fileName.GetLength());
					int nLen = MultiByteToWideChar(CP_ACP, 0,lpStr, -1, NULL, NULL);
					MultiByteToWideChar(CP_ACP, 0, lpStr, -1, lpszW, nLen);
					tmpstr.Format("Adding track %d - %s", i+1, pObject->GetName());
					pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)tmpstr.GetBuffer(0));
		
					// get a stream to write to the disc
					hr = SHCreateStreamOnFileW(lpszW, STGM_READWRITE, &testStream);
					if (FAILED(hr))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to get file stream"));
					}
					if (SUCCEEDED(hr))
					{
						hr = testStream->Stat(&stat, STATFLAG_DEFAULT);
						if (FAILED(hr))
						{
							pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to get test stream stat"));
						}
					}
					// Mod the size so that it is 2352 byte aligned
					if (SUCCEEDED(hr))
					{
					ULARGE_INTEGER newSize;
					newSize.HighPart = stat.cbSize.HighPart;
					newSize.LowPart = stat.cbSize.LowPart - (stat.cbSize.LowPart%2352);
					hr = testStream->SetSize(newSize);
					if (FAILED(hr))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to Set Size"));
					}
				}
				if (SUCCEEDED(hr))
				{
					//Add the track to the stream
					hr = raw->AddTrack(IMAPI_CD_SECTOR_AUDIO, testStream, &index);
					if (FAILED(hr))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("FAILED AddTrack(testStream)"));
					}
					delete[] lpszW;
					//DeleteFile(outfile);
					if (testStream != NULL)
					{ 
						testStream->Release();
						testStream = NULL; 
					}              
				}
				// Did user cancel?
				if (pThis->GetCancelBurning())
				{
					i = pThis->m_fileListbox.GetCount(); // for loop to drop out.
				}
				pThis->m_ProgressTrack.SetPos(i+1);
				
				int percent = (100*(i+1)) / pThis->m_fileListbox.GetCount();
				//if (percent == 99)
				//	percent = 100;
				CString cPercent;
				cPercent.Format("Converting Track Progress %d%%", percent);
				pThis->m_progressTrackText.SetWindowText(cPercent);
				//pThis->m_progressCtrl.SetPos(i+1);
				}
				pThis->m_progressTrackText.SetWindowText("Track conversion complete");
				pThis->m_ProgressTrack.SetPos(100);
				// create the disc image    
				if (SUCCEEDED(hr))
				{
					raw->CreateResultImage(&streamData);
					if (FAILED(hr))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("FAILED raw->CreateResultImage"));
					}
				}
				IMAPI_MEDIA_PHYSICAL_TYPE mediaType;
				hr = pDiscFormatRawCD->get_CurrentPhysicalMediaType(&mediaType);
				if (SUCCEEDED(hr))
				{
					VARIANT_BOOL rotation = VARIANT_TRUE;
					if (pThis->m_CheckUseCAV.GetCheck() == 0)
						rotation = VARIANT_FALSE;
					hr = pDiscFormatRawCD->SetWriteSpeed((LONG)pThis->GetSpeedSecsPerSecond(mediaType), rotation); //last parameter is VARIANT_TRUE for CAV or VARIANT_FALSE for other the drive supports,  default is VARIANT FALSE
				}
				VARIANT_BOOL vbool = pThis->m_BurnProof.GetCheck()?VARIANT_FALSE:VARIANT_TRUE; //VARIANT_FALSE means burn proof enabled
				hr = pDiscFormatRawCD->put_BufferUnderrunFreeDisabled(vbool);
				discFormatRawCD.Burn(pThis->m_hWnd, streamData);
			}
			discFormatRawCD.FreeRecorder();
			discRecorder.ReleaseExclusiveAccess();
		}
		else
		{
			pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Failed to get exclusive access"));
		}
		// Eject Media if they chose
		CString num;
		pThis->m_NumberofCopies.GetWindowTextA(num.GetBuffer(10), 10);
		num.ReleaseBuffer();
		if (atoi(num) > 1)// || pThis->m_nNumberofCopies > 1
		{
			if (pThis->m_nNumberofCopies > 1)
			{
				discRecorder.EjectMedia();
				pThis->DoNextCopy();
				raw->Release();
				if (streamData != NULL)
				{ 
					streamData->Release();
					streamData = NULL; 
				}   
				for (int i=0; i< pThis->m_fileListbox.GetCount(); i++)
				{
					if (carray[i] == "")
						break;
					int result = DeleteFile(carray[i]);
				}
				delete [] carray;
				return 0;
			}
		}
	}
	else
	{
		pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Failed initialize burner"));
	}
	if (pThis->m_ejectWhenFinished.GetCheck())
	{
		discRecorder.EjectMedia();	
	}	
	raw->Release();
	// Finished Burning, GetHresult will determine if it was successful or not
	pThis->SendMessage(WM_BURN_FINISHED, discFormatRawCD.GetHresult(), (LPARAM)(LPCTSTR)discFormatRawCD.GetErrorMessage());
	
	if (pThis->GetCancelBurning())
	{
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Music CD cancelled"));
	}
	else
	{
		if (SUCCEEDED(hr))
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Music CD complete"));
			pThis->m_progressCtrl.SetPos(pThis->m_fileListbox.GetCount()*100);
			if ( pThis->m_pTaskbarList )
				pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, 100, 100);
		}
		else
		{
		   pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Music CD failed"));
		}
	}           
	if (streamData != NULL)
	{ 
		streamData->Release();
		streamData = NULL; 
	}   
	for (int i=0; i< pThis->m_fileListbox.GetCount(); i++)
	{
		if (carray[i] == "")
			break;
		int result = DeleteFile(carray[i]);
	}
	delete [] carray;
	pThis->m_progressTrackText.EnableWindow(FALSE);
	//pThis->m_nCurrentMode = PROGRAM_IDLE;
	pThis->EnableUI(TRUE);
	return 0;
}

UINT CBurnCDDlg::AudioThread(LPVOID pParam)
{
	CBurnCDDlg* pThis						= (CBurnCDDlg*)pParam;
	HRESULT hr								= S_OK;
	BOOLEAN bReturn							= TRUE;
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	
	ULONG selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		pThis->m_progressTrackText.EnableWindow(FALSE);
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"No drive selected");
		return -1;
	}
	CDiscFormatTrackAtOnce discFormatTrackAtOnce;
	IDiscFormat2TrackAtOnce *pIDiscFormatTrackAtOnce;
	CDiscRecorder* pOrigDiscRecorder = (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	// Create another disc recorder because we're in a different thread
	CDiscRecorder discRecorder;
	if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
	{
		if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
		{
			discFormatTrackAtOnce.pThis = pThis;
			if (!discFormatTrackAtOnce.Initialize(&discRecorder, CLIENT_NAME) != NULL)
			{
				pThis->m_progressTrackText.EnableWindow(FALSE);
				pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)(LPCTSTR)"discFormatTrackAtOnce.Initialize failed");
				return -1;
			}
			pIDiscFormatTrackAtOnce = discFormatTrackAtOnce.GetIDiscFormatTrackAtOncePtr();
			//IMAPI_MEDIA_PHYSICAL_TYPE value;
			//HRESULT hRes = pIDiscFormatTrackAtOnce->get_CurrentPhysicalMediaType(&value);
			pThis->m_nCurrentMode = AUDIOCD_DISC;
			// Add all the tracks from the list control
			if (SUCCEEDED(hr))
			{
				CString tmpstr;
				CBaseObject* pObject;
				pThis->m_TotalAudioTracks = 0;
				pThis->m_progressCtrl.SetRange(0, pThis->m_fileListbox.GetCount());
				pThis->m_TotalAudioTracks = pThis->m_fileListbox.GetCount();
				for (int i=0; i < pThis->m_fileListbox.GetCount(); i++)
				{
					pObject = (CBaseObject*)pThis->m_fileListbox.GetItemDataPtr(i);
					ASSERT(pObject != NULL);
					if (pObject == NULL)
					{
						pThis->m_TotalAudioTracks--;
						continue;
					}
					CString fileName = pObject->GetPath();
					
					if (pThis->isDirectory(fileName.GetBuffer(0)))
					{
						//folders are not allowed
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Skipping folder item in the list"));
						pThis->m_TotalAudioTracks--;
						continue;	
					} 
					// We have a file, let's add it
					IStream * testStream = NULL;
					STATSTG stat;
			
					CString temp, path, outfile;
					temp = fileName.Right(3);
					temp.MakeLower();
					if (temp == "mp3")
					{
						CString str;
						str.Format(_T("Converting %s"), pObject->GetName());
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str.GetBuffer(0));
						GetTempPath(MAX_PATH, temp.GetBuffer(MAX_PATH));
						temp.ReleaseBuffer();
						path = temp;
						int idx = fileName.ReverseFind(_T('\\'));
						temp = fileName.Mid(idx+1);
						temp = temp.Left(temp.GetLength()-3);
						outfile.Format("%s%s%s", path, temp, "wav");
						int stat = pThis->ConvertMP3toWAV(&fileName,  &outfile);
						if (stat != 0)
						{
							pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Error converting mp3"));
							pThis->m_TotalAudioTracks--;
							continue;
						}
						fileName = outfile;
					}
					else if (temp != "wav")
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Skipping invalid file"));
						pThis->m_TotalAudioTracks--;
						continue;
					}
					LPWSTR lpszW = new WCHAR[255];
					LPTSTR lpStr = fileName.GetBuffer(fileName.GetLength());
					int nLen = MultiByteToWideChar(CP_ACP, 0,lpStr, -1, NULL, NULL);
					MultiByteToWideChar(CP_ACP, 0, lpStr, -1, lpszW, nLen);
					tmpstr.Format("Adding track %d - %s", i+1, pObject->GetName());
					pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)tmpstr.GetBuffer(0));
					// get a stream to write to the disc
					hr = SHCreateStreamOnFileW(lpszW, STGM_READWRITE, &testStream);
					if (FAILED(hr))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to get file stream"));
					}
					if (SUCCEEDED(hr))
					{
						hr = testStream->Stat(&stat, STATFLAG_DEFAULT);
						if (FAILED(hr))
						{
							pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to get test stream stat"));
						}
					}
					// Mod the size so that it is 2352 byte aligned
					if (SUCCEEDED(hr))
					{
						ULARGE_INTEGER newSize;
						newSize.HighPart = stat.cbSize.HighPart;
						newSize.LowPart = stat.cbSize.LowPart - (stat.cbSize.LowPart%2352);
						hr = testStream->SetSize(newSize);
						if (FAILED(hr))
						{
							pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to Set Size"));
						}
					}
					if (SUCCEEDED(hr))
					{
						//write the stream
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Writing track now..."));
						
						hr = discFormatTrackAtOnce.BurnTrack(pThis->m_hWnd, testStream);
						if (FAILED(hr))
						{
							pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to Add Audio Track"));
						}
						pThis->m_ProgressTrack.SetPos(100);
					}
					// Did user cancel?
					if (pThis->GetCancelBurning())
					{
						i = pThis->m_fileListbox.GetCount(); // for loop to drop out.
					}
					delete[] lpszW;
					
					if (testStream != NULL)
					{ 
						testStream->Release();
						testStream = NULL; 
					}
					DeleteFile(outfile);   
				}
			}
		
			CString num;
			pThis->m_NumberofCopies.GetWindowTextA(num.GetBuffer(10), 10);
			num.ReleaseBuffer();
			if (atoi(num) > 1)// || pThis->m_nNumberofCopies > 1
			{
				discRecorder.EjectMedia();
				if (pThis->m_nNumberofCopies > 1)
				{
					pThis->DoNextCopy();
					discFormatTrackAtOnce.FreeRecorder();
					discRecorder.ReleaseExclusiveAccess();
					return 0;
				}
			}
			// Eject Media if they chose
			if (pThis->m_ejectWhenFinished.GetCheck())
			{
				discRecorder.EjectMedia();	
			}	
			// Finished Burning, GetHresult will determine if it was successful or not
			pThis->SendMessage(WM_BURN_FINISHED, discFormatTrackAtOnce.GetHresult(), (LPARAM)(LPCTSTR)discFormatTrackAtOnce.GetErrorMessage());
			discFormatTrackAtOnce.FreeRecorder();
			discRecorder.ReleaseExclusiveAccess();
		}
		else
		{
			pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed to get exclusive access"));
		}
		//pThis->m_nCurrentMode = PROGRAM_IDLE;
		if (pThis->GetCancelBurning())
		{
			pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Music CD cancelled"));
		}
		else
		{
			if (SUCCEEDED(hr))
			{
				pThis->SendMessage(WM_BURN_FINISHED, 0, (LPARAM)_T("Audio write complete"));
				pThis->m_progressCtrl.SetPos(pThis->m_fileListbox.GetCount()*100);
				if ( pThis->m_pTaskbarList )
					pThis->m_pTaskbarList->SetProgressState ( pThis->m_hWnd, TBPF_NOPROGRESS );
			}
			else
			{
			   pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Audio write failed"));
			}
		}
	}
	else
	{
		pThis->SendMessage(WM_BURN_FINISHED, hr, (LPARAM)_T("Failed to initialize burner"));
	}
	pThis->EnableUI(TRUE);
	pThis->m_progressTrackText.EnableWindow(FALSE);
	return 0;
}

//Added by Nic  Burn routine for writing ISO files
UINT CBurnCDDlg::WriteBinThread(LPVOID pParam)
{
	CBurnCDDlg* pThis	= (CBurnCDDlg*)pParam;
	// Get the selected recording device from the combobox
	int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	ASSERT(selectedIndex >= 0);
	if (selectedIndex < 0)
	{
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Error: No device selected"));
		return 0;
	}
	CDiscFormatRawCD discFormatRawCD;
	IDiscFormat2RawCD* pDiscFormatRawCD;
	CDiscRecorder* pOrigDiscRecorder = 		(CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (pOrigDiscRecorder == NULL)
	{
		// This should never happen
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Error: pOrigDiscRecorder is NULL"));
		return 0;
	}
	// Did user cancel?
	if (pThis->GetCancelBurning())
	{
		pThis->SendMessage(WM_BURN_FINISHED, -3, (LPARAM)_T("Write ISO cancelled"));
		return 0;
	}
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Preparing burner..."));
	// Create another disc recorder because we're in a different thread
	CDiscRecorder discRecorder;
	CString errorMessage;
	if (discRecorder.Initialize(pOrigDiscRecorder->GetUniqueId()))
	{
		if (discRecorder.AcquireExclusiveAccess(true, CLIENT_NAME))
		{
			discFormatRawCD.pThis = pThis;			
			if (discFormatRawCD.Initialize(&discRecorder, CLIENT_NAME) != NULL)
			{
				pDiscFormatRawCD = (IDiscFormat2RawCD*)discFormatRawCD.GetIDiscFormatRawCDPtr();
				VARIANT_BOOL vbool = pThis->m_BurnProof.GetCheck()?VARIANT_FALSE:VARIANT_TRUE; //VARIANT_FALSE means burn proof enabled
				pDiscFormatRawCD->put_BufferUnderrunFreeDisabled(vbool);
	
				// Get the media type currently in the recording device
				IStream* dataStream = NULL;
				CString file = pThis->ISOfile;
				HRESULT hr = SHCreateStreamOnFile((LPCTSTR)file.GetBuffer(0), STGM_READWRITE, &dataStream);
				if (FAILED(hr))
				{	// SHCreateStreamOnFile reported error to UI
					pThis->SendMessage(WM_BURN_STATUS_MESSAGE, -2, (LPARAM)_T("SHCreateStreamOnFile reported error"));
					pThis->m_nCurrentMode = PROGRAM_IDLE;
					return false;
				}
				
				// Write the ISO
				//pDiscFormatRawCD->put_RequestedSectorType(IMAPI_FORMAT2_RAW_CD_SUBCODE_IS_RAW);
				IMAPI_MEDIA_PHYSICAL_TYPE mediaType;
				hr = pDiscFormatRawCD->get_CurrentPhysicalMediaType(&mediaType);
				if (SUCCEEDED(hr))
				{
					VARIANT_BOOL rotation = VARIANT_TRUE;
					if (pThis->m_CheckUseCAV.GetCheck() == 0)
						rotation = VARIANT_FALSE;
					hr = pDiscFormatRawCD->SetWriteSpeed((LONG)pThis->GetSpeedSecsPerSecond(mediaType), rotation); //last parameter is VARIANT_TRUE for CAV or VARIANT_FALSE for other the drive supports,  default is VARIANT FALSE
				}
				STATSTG stat;
				dataStream->Stat(&stat, sizeof(stat) );
				// Mod the size so that it is 2352 byte aligned
				if (SUCCEEDED(hr))
				{
					ULARGE_INTEGER newSize;
					newSize.HighPart = stat.cbSize.HighPart;
					newSize.LowPart = stat.cbSize.LowPart - (stat.cbSize.LowPart%2352);
					hr = dataStream->SetSize(newSize);
					if (FAILED(hr))
					{
						pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to Set Size"));
					}
				}
				discFormatRawCD.Burn(pThis->m_hWnd, dataStream);
				// Release the IStream after burning
				dataStream->Release();
				CString num;
				pThis->m_NumberofCopies.GetWindowTextA(num.GetBuffer(10), 10);
				num.ReleaseBuffer();
				if (atoi(num) > 1)// || pThis->m_nNumberofCopies > 1
				{
					discRecorder.EjectMedia();
					if (pThis->m_nNumberofCopies > 1)
					{
						pThis->DoNextCopy();
						discFormatRawCD.FreeRecorder();
						return 0;
					}
				}
				// Eject Media if they chose
				if (pThis->m_ejectWhenFinished.GetCheck())
				{
					discRecorder.EjectMedia();	
				}	
			}
			discFormatRawCD.FreeRecorder();
			discRecorder.ReleaseExclusiveAccess();
			// Finished Burning, GetHresult will determine if it was successful or not
			pThis->SendMessage(WM_BURN_FINISHED, discFormatRawCD.GetHresult(), (LPARAM)(LPCTSTR)discFormatRawCD.GetErrorMessage());
		}
		else
		{
			errorMessage.Format(_T("Failed: %s is exclusive owner"),
				(LPCTSTR)discRecorder.ExclusiveAccessOwner());
			pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(), 
				(LPARAM)(LPCTSTR)errorMessage);
		}
	}
	else
	{
		errorMessage.Format(_T("Failed to prepare burner - Unique ID:%s"),
			(LPCTSTR)pOrigDiscRecorder->GetUniqueId());
		pThis->SendMessage(WM_BURN_FINISHED, discRecorder.GetHresult(), (LPARAM)(LPCTSTR)errorMessage);
	}
	pThis->EnableUI(TRUE);	
	return 0;
}

//Added by Nic  Burn routine for writing ISO files
UINT CBurnCDDlg::WriteISOHddThread(LPVOID pParam)
{
	CBurnCDDlg* pThis = (CBurnCDDlg*)pParam;
	CString filename;
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	CString initialdir = GetString("WriteISOPath", "");
	CFileDialog fileDialog(FALSE, "iso", NULL, NULL, _T("ISO File (*.iso)|*.iso|All Files (*.*)|*.*||"), NULL, 0);
	fileDialog.GetOFN().lpstrTitle = "Choose a path and filename to write  the ISO file";
	fileDialog.GetOFN().lpstrInitialDir = initialdir;
	if (fileDialog.DoModal() == IDOK)
		filename = fileDialog.GetPathName();
	else
	{
		pThis->m_nCurrentMode = PROGRAM_IDLE;
		return 1;
	}
	int findIndex = filename.ReverseFind(_T('\\'));
	CString path = filename.Left(findIndex+1);
	WriteString("WriteISOPath", path);
	int nUDFRev = -1;   
	// Create the file system
	IStream* dataStream = NULL;
	int nFileSystem = pThis->GetFileSystem();
	if (nFileSystem == FSi_AUDIOCD || nFileSystem == FSi_AUDIOCD_DAO)
	{
		//This should never occur
		pThis->MessageBox("Fatal Error, Audio CD filesystem chosen for data disc");
		pThis->m_nCurrentMode = PROGRAM_IDLE;
		return 0;
	}
	if (nFileSystem == FS_AUTO)
	{
		nFileSystem = pThis->m_nAutoFileSystem;
		if (nFileSystem == -1)
		{
			nFileSystem = FsiFileSystemISO9660|FsiFileSystemJoliet;
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Joliet File System Auto selected"));
		}
	}
	if (nFileSystem & FsiFileSystemUDF)
	{
		nUDFRev = pThis->GetUDFRevision();
		{
			if (nUDFRev == UDF_AUTO)
			{
				nUDFRev = pThis->m_AutoUDFVersion;
			}
		}
	}
	VARIANT_BOOL varbool = VARIANT_TRUE;
	if (!CreateFileSystemForISO(pThis, &dataStream, (FsiFileSystems)nFileSystem, nUDFRev))
	{	
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("CreateFileSystemForISO reported error"));
		pThis->m_nCurrentMode = PROGRAM_IDLE;
		return false;
	}
	IStream* OutStream = NULL;
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Writing ISO..."));
	
	HRESULT hr = SHCreateStreamOnFile((LPCTSTR)filename.GetBuffer(0), 	STGM_READWRITE|	STGM_CREATE| STGM_SHARE_DENY_WRITE, &OutStream);
	if (FAILED(hr))
	{	// SHCreateStreamOnFile reported error to UI
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("SHCreateStreamOnFile reported error"));
		pThis->m_nCurrentMode = PROGRAM_IDLE;
		return false;
	}
	STATSTG stat;
	ULARGE_INTEGER ULInc;
	dataStream->Stat(&stat, 0x01);
	ULARGE_INTEGER StreamSize = stat.cbSize;
	__int64 incSize = StreamSize.QuadPart / 100;
	ULInc.QuadPart = incSize;
	ULInc.HighPart = (unsigned int) (incSize>>32);
	ULInc.LowPart = (unsigned int) incSize;
	ULARGE_INTEGER pcbRead, pcbWritten;
	pThis->m_progressCtrl.SetRange32(0, 100);
	CString text;
	for (int i = 0; i <100; i++)
	{
		if (i==99)
		{
			__int64 lastsize = StreamSize.QuadPart - (incSize*98);
			ULInc.QuadPart = lastsize;
			ULInc.HighPart = (unsigned int) (lastsize>>32);
			ULInc.LowPart = (unsigned int) lastsize;
		}
		dataStream->CopyTo(OutStream, ULInc, &pcbRead, &pcbWritten);
		if (SUCCEEDED(hr))
		{
			text.Format(_T("Progress: %d%%"), i);
			pThis->m_progressText.SetWindowText(text);
			pThis->m_progressCtrl.SetPos(i);
			if ( pThis->m_pTaskbarList )
				pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, i,100);
		}
		else
		{
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Error writing stream to file"));
			dataStream->Release();
			OutStream->Release();
			pThis->m_nCurrentMode = PROGRAM_IDLE;
		return false;
		}
	}
	pThis->m_progressCtrl.SetPos(100);
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, 100, 100);
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("ISO Successfully written"));
	dataStream->Release();
	OutStream->Release();
	CString tmp;
	tmp.Format("ISO Successfully written to %s", filename);
	pThis->MessageBox(tmp);
	pThis->m_nCurrentMode = PROGRAM_IDLE;
	pThis->EnableUI(TRUE);
	return 0;
}

void CBurnCDDlg::SetISOBurn()
{
	UpdateData(TRUE);
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	if (m_RadioBurnFilesFolders == 1)
	{
		GetDlgItem(IDC_VOLUME)->EnableWindow(FALSE);
		GetDlgItem(IDC_STATICVOLUME)->EnableWindow(FALSE);
		GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(FALSE);
		GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(FALSE);
		if (m_fileListbox.GetCount() > 1)
		{
			MessageBox("You have more than one file in the list.  You can only burn a single file as an ISO image.\n\nBurn As ISO will be disabled", "Wrong number of files", MB_ICONSTOP);
			m_RadioBurnFilesFolders = 0;
			GetDlgItem(IDC_VOLUME)->EnableWindow(TRUE);
			GetDlgItem(IDC_STATICVOLUME)->EnableWindow(TRUE);
			GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(TRUE);
			GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(TRUE);
			UpdateData(FALSE);
			
		}
		else if (m_fileListbox.GetCount() == 0)
			return;  //OK State
		else
		{
			CString fname, ext;
			m_fileListbox.GetText(0, fname);
			int findIndex = fname.ReverseFind(_T('.'));
			ext = fname.Mid(findIndex+1);
			ext.MakeLower();
			if (ext != "iso" && ext != "bin")
			{
				MessageBox("The file in the list does not appear to be an ISO image", "ISO Image?", MB_ICONINFORMATION);
			}
		}
	}
	else
	{
		GetDlgItem(IDC_VOLUME)->EnableWindow(TRUE);
		GetDlgItem(IDC_STATICVOLUME)->EnableWindow(TRUE);
		GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(TRUE);
		GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(TRUE);
	}
}

/* NOTE: Drop messages are not sent when run from the IDE you have to run it externally.*/
void CBurnCDDlg::OnDropFiles(HDROP hDropInfo)
{
	CString FileName, tmpstr;
	if ( pThis->m_pTaskbarList )
		pThis->m_pTaskbarList->SetProgressState( pThis->m_hWnd, TBPF_INDETERMINATE);
	HDROP p_hDropInfo = hDropInfo;	 				
	int DropTotal = DragQueryFile(hDropInfo, 0xFFFFFFFF,	NULL, NULL);	//the number of files dropped.
	for(int loop = 0; loop < DropTotal; loop++)
	{
		DragQueryFile(hDropInfo, loop, FileName.GetBuffer(MAX_PATH), MAX_PATH);						//then again to get the file, 
		FileName.ReleaseBuffer();
		if (isDirectory(FileName))
		{
			if (doesNameExistinList(&FileName))
			{
				tmpstr.Format("The folder: %s already exists in the list.\n\nAre you sure you want to add it again?", FileName);
				if (MessageBox(tmpstr, "Are you sure?", MB_ICONQUESTION|MB_YESNO) == IDNO)
					continue;
			}
			SetWaitCursor(TRUE);
			//m_TotalSizeText.SetWindowText("Checking folder");
			CDirObject* pDirObject = new CDirObject(FileName);
			int findIndex = FileName.ReverseFind(_T('\\'));
			int addIndex = m_fileListbox.AddString(FileName.Mid(findIndex+1));
			m_fileListbox.SetItemDataPtr(addIndex, pDirObject);
			SetWaitCursor(FALSE);
		}
		else
		{
			if (doesNameExistinList(&FileName))
			{
				tmpstr.Format("The file: %s already exists in the list.\n\nAre you sure you want to add it again?", FileName);
				if (MessageBox(tmpstr, "Are you sure?", MB_ICONQUESTION|MB_YESNO) == IDNO)
					continue;
			}
			CFileObject* pFileObject = new CFileObject(FileName);
			int findIndex = FileName.ReverseFind(_T('\\'));
			int addIndex = m_fileListbox.AddString(FileName.Mid(findIndex+1));
			m_fileListbox.SetItemDataPtr(addIndex, pFileObject);
		}
		if (loop == 0)
			UpdateCapacity();
		else
			UpdateCapacity(TRUE);
		EnableBurnButton();
	}
	CDialog::OnDropFiles(hDropInfo);
}

BOOL CBurnCDDlg::isDirectory(LPCTSTR szPath)
{
	DWORD dwAttrib = GetFileAttributes(szPath);
	return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
			(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}


void CBurnCDDlg::OnClickedRadioburnfiles()
{
	UpdateData(TRUE);
	GetDlgItem(IDC_STATICFILESYSTEM)->EnableWindow(TRUE);
	GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
	GetDlgItem(IDC_COMBO_FILESYSTEM)->EnableWindow(TRUE);
	GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
	if (m_FileSystemCombo.GetCurSel() == FS_AUDIOCD || m_FileSystemCombo.GetCurSel() == FS_AUDIOCD_DAO)
		m_StaticListWindow.SetWindowTextA("Add or Drag music files to burn (MP3 or WAV)"); 
	else
		m_StaticListWindow.SetWindowTextA("Add or Drag folders && files to burn"); 
	SetISOBurn();
	EnableBurnButton();
	UpdateData(FALSE);
}


void CBurnCDDlg::OnRadioburniso()
{
	UpdateData(TRUE);
	GetDlgItem(IDC_STATICFILESYSTEM)->EnableWindow(FALSE);
	GetDlgItem(IDC_STATICUDFREV)->EnableWindow(FALSE);
	GetDlgItem(IDC_COMBO_FILESYSTEM)->EnableWindow(FALSE);
	GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
	m_StaticListWindow.SetWindowTextA("Add or Drag an ISO file to burn"); 
	SetISOBurn();
	EnableBurnButton();
	UpdateData(FALSE);
}

void CBurnCDDlg::OnSelchangeComboIsomode()
{
	UpdateData(TRUE);
}


void CBurnCDDlg::OnClickedCheckFullerase()
{
	UpdateData(TRUE);
}


HRESULT CBurnCDDlg::GetSupportedWriteSpeedDescriptors(IMAPI_MEDIA_PHYSICAL_TYPE *pMediaType, SAFEARRAY** pVal)
{
	HRESULT hRes=S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return 1;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return 1;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		HRESULT hRes = pIDiscFormatData->get_SupportedWriteSpeedDescriptors(pVal);
		if(SUCCEEDED(hRes))
		{
			 IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
				discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
				*pMediaType = mediaType;
			return hRes;
		}
	}
	return 1;
}


HRESULT CBurnCDDlg::GetSupportedWriteSpeeds(IMAPI_MEDIA_PHYSICAL_TYPE *pMediaType, SAFEARRAY** pVal)
{
	HRESULT hRes=S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return 1;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return 1;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		HRESULT hRes = pIDiscFormatData->get_SupportedWriteSpeeds(pVal);
		if(SUCCEEDED(hRes))
		{
			 IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
				discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
				*pMediaType = mediaType;
			return hRes;
		}
	}
	return 1;
}

IMAPI_MEDIA_PHYSICAL_TYPE CBurnCDDlg::GetCurrentMediaType()
{
	int selectedIndex = m_deviceComboBox.GetCurSel();
	IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
	if (selectedIndex < 0)
	{
		return mediaType;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return mediaType;
		}
		discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);	
	}
	return mediaType;
}

void CBurnCDDlg::FillSpeedsComboBox()
{

	//TEST FOR MEDIA PRESENT

	//Get the SAFEARRAY from the supported speeds
	//Then extract each element which is a Variant
	//The type we want is in iVal and are VT_I4 type
	//Which are sectors per seconds written
	int prev = m_MediaSpeeds.GetCurSel();
	if (prev < 0)
		prev = 0;
	m_MediaSpeeds.ResetContent();
	int index = 0;
	m_MediaSpeeds.AddString("Auto");
	index++;
	IMAPI_MEDIA_PHYSICAL_TYPE pMediaType;
	IMAPI_MEDIA_PHYSICAL_TYPE pMediaType1;
	SAFEARRAY *pVal = NULL;
	SAFEARRAY *pVal1 = NULL;
	LONG speed = 0;
	HRESULT hRes1 = GetSupportedWriteSpeedDescriptors(&pMediaType1, &pVal1);
	if (hRes1 == S_OK)
	{
		long nIRTypes1 = pVal1->rgsabound->cElements;
		for( LONG irType = 0; irType < nIRTypes1; ++irType )
		{
			VARIANT v;
			SafeArrayGetElement(pVal1, &irType, &v);
			IWriteSpeedDescriptor *wsp = (IWriteSpeedDescriptor *)v.pdispVal;
			
			wsp->get_WriteSpeed(&speed);
		}
	}
	HRESULT hRes = GetSupportedWriteSpeeds(&pMediaType, &pVal);
	if (hRes != S_OK)
		return;
	long nIRTypes = pVal->rgsabound->cElements;
	for( LONG irType = 0; irType < nIRTypes; ++irType )
	{
		VARIANT v;
		SafeArrayGetElement(pVal, &irType, &v);
		LONG divisor = GetSpeedDivisor((LONG)pMediaType);
//		double KBps = ((double)v.iVal * 2.048);
//		double speed = KBps / divisor;
		double KBps = ((double)v.iVal * 2048);
		double speed = KBps / (divisor * 1024);
		
		CString speedstr;
		//speedstr.Format("%dKBps (%4.1fx)", (int)KBps, speed);
		if (speed != 2.4) //skip rounding for +R 2.4x
			speed = (double)(int)speed;
		if ((int)speed == 3)
			speed = 4;
		else if ((int)speed == 5)
			speed = 6;
		if ((int)speed % 2)
			speed += 1;

		speedstr.Format("%4.1fx", speed);
		m_MediaSpeeds.AddString(speedstr);
		m_MediaSpeeds.SetItemData(index++, (DWORD_PTR)v.iVal);
	}
	if (prev < 0)
		prev = 0;
	m_MediaSpeeds.EnableWindow(TRUE);
	m_MediaSpeeds.SetCurSel(prev);
	//UpdateData(FALSE);
}

BOOL CBurnCDDlg::GetBufferUnderrunEnabled()
{
	HRESULT hRes=S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return NULL;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return 0;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		VARIANT_BOOL varbool = 0;
		hRes = pIDiscFormatData->get_BufferUnderrunFreeDisabled(&varbool);
		if(SUCCEEDED(hRes))
		{
			if (varbool == VARIANT_TRUE)
				return FALSE;  //VARIANT_TRUE means its disabled
		}	
	}
	return TRUE;
}

BOOL CBurnCDDlg::SetBufferUnderrunMode(VARIANT_BOOL set)
{
	HRESULT hRes=S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return 0;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return 0;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		hRes = pIDiscFormatData->put_BufferUnderrunFreeDisabled(set);//VARIANT_FALSE means burn proof enabled
		if(SUCCEEDED(hRes))
			return TRUE;
	}
	return FALSE;
}

void CBurnCDDlg::OnClickedCheckBurnproof()
{
	UpdateData(TRUE);
	if (m_BurnProof.GetCheck())
		SetBufferUnderrunMode(VARIANT_FALSE); //VARIANT_FALSE means enabled it
	else
		SetBufferUnderrunMode(VARIANT_TRUE); //VARIANT_TRUE means disable it
}

LONG CBurnCDDlg::GetTotalSectors(void)
{
	HRESULT hRes=S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return -1;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return -1;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
		discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
		if (mediaType == IMAPI_MEDIA_TYPE_UNKNOWN)
			return -1;
		LONG totalsectors;
		hRes = pIDiscFormatData->get_TotalSectorsOnMedia(&totalsectors);
		if(SUCCEEDED(hRes))
		{
			return totalsectors;
		}
	}
	return -1;
}

LONG CBurnCDDlg::GetFreeSectors(void)
{
	HRESULT hRes=S_OK;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return -1;
	}
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return -1;
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
		discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);
		if (mediaType == IMAPI_MEDIA_TYPE_UNKNOWN)
			return -1;
		LONG freesectors;
		hRes = pIDiscFormatData->get_FreeSectorsOnMedia(&freesectors);
		if(SUCCEEDED(hRes))
		{
			return freesectors;
		}
	}
	return -1;
}


void CBurnCDDlg::OnSelchangeComboVerify()
{
	UpdateData(TRUE);
}


void CBurnCDDlg::OnSelchangeComboMediaSpeeds()
{
	UpdateData(TRUE);
}
/*
double CBurnCDDlg::GetSpeedSecsPerSecond()
{
	HRESULT hRes=S_OK;
	CString spdstr;
	double SecsPerSec =  -1;  // -1 default value for max speed drive supports.
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
	{
		return -1;  // -1 is max speed incase of failure here
	}
	int selection = m_MediaSpeeds.GetCurSel();
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder != NULL)
	{
		CDiscFormatData discFormatData;
		if  (!discFormatData.Initialize(discRecorder, CLIENT_NAME))
		{
			return -1;// -1 is max speed incase of failure here
		}
		pIDiscFormatData = discFormatData.GetIDiscFormat2DataPtr();
		IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
		discFormatData.GetInterface()->get_CurrentPhysicalMediaType(&mediaType);

		if (selection > 0)
		{
			m_MediaSpeeds.GetLBText(selection, spdstr);
			spdstr.Delete(spdstr.GetLength()-1, 1);
			double val = atof(spdstr.GetBuffer(0));
			double bps;
			if (mediaType > IMAPI_MEDIA_TYPE_CDROM && mediaType <= IMAPI_MEDIA_TYPE_CDRW) //CD
			{
				bps = 75.0;
				SecsPerSec = val * bps;
			}
			else if (mediaType >= IMAPI_MEDIA_TYPE_DVDROM && mediaType <= IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER && mediaType != IMAPI_MEDIA_TYPE_DISK) //DVD
			{
				bps = 676;
				SecsPerSec = val * bps;
			}
			else if (mediaType >= IMAPI_MEDIA_TYPE_HDDVDROM && mediaType <= IMAPI_MEDIA_TYPE_HDDVDRAM) //HD-DVD
			{
				bps = 2178;
				SecsPerSec = val * bps;
			}
			else if (mediaType >= IMAPI_MEDIA_TYPE_BDROM && mediaType <= IMAPI_MEDIA_TYPE_BDRE) //Bluray
			{
				bps = 2194;
				SecsPerSec = val * bps;
			}
			else 
				SecsPerSec = -1;// -1 is max speed for AUTO mode
		}
	}
	return SecsPerSec;
}*/

DWORD_PTR CBurnCDDlg::GetSpeedSecsPerSecond(IMAPI_MEDIA_PHYSICAL_TYPE mediaType)
{
	//CString spdstr;
	//double SecsPerSec = -1;  // -1 default value for max speed drive supports.
	int selection = m_MediaSpeeds.GetCurSel();
	if ( selection == 0)
		selection = 1;					//fastest
	if (selection < 0)
	{
		m_MediaSpeeds.SetCurSel(0);
		UpdateData(FALSE);
		return -1;
	}
	return m_MediaSpeeds.GetItemData(selection);
}

LONG CBurnCDDlg::GetSpeedDivisor(LONG MediaType)
{
	switch (MediaType)
	{
		case IMAPI_MEDIA_TYPE_UNKNOWN:
		case IMAPI_MEDIA_TYPE_DISK:
		default:
			return 0;
		case IMAPI_MEDIA_TYPE_CDROM:
		case IMAPI_MEDIA_TYPE_CDR:
		case IMAPI_MEDIA_TYPE_CDRW:
			//CD 150KBps = 75 sectors/sec
			return 150;
		break;
		case IMAPI_MEDIA_TYPE_DVDROM:
		case IMAPI_MEDIA_TYPE_DVDRAM:
		case IMAPI_MEDIA_TYPE_DVDPLUSR:
		case IMAPI_MEDIA_TYPE_DVDPLUSRW:
		case IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:
		case IMAPI_MEDIA_TYPE_DVDDASHR:
		case IMAPI_MEDIA_TYPE_DVDDASHRW:
		case IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
		case IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
		case IMAPI_MEDIA_TYPE_BDROM:
			//DVD 1385 = 676.25 sectors/sec
			return 1352;
		break;
		case IMAPI_MEDIA_TYPE_BDR:
		case IMAPI_MEDIA_TYPE_BDRE:
			//BD 4495 = 2195 sectors/sec
			return 4390;   //KBytes sec
		break;
		case IMAPI_MEDIA_TYPE_HDDVDROM:
		case IMAPI_MEDIA_TYPE_HDDVDR:
		case IMAPI_MEDIA_TYPE_HDDVDRAM:
			//HD-DVD 4462 = 2178 sectors/sec
			return 4356;
		break;
	 }
	return 0;
}


SAFEARRAY* CBurnCDDlg::GetSupportedUDFRevisions()
{
	SAFEARRAY* pVal = NULL;
	int selectedIndex = m_deviceComboBox.GetCurSel();
	CDiscRecorder *pdiscRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (pdiscRecorder == NULL)
	{
		m_deviceComboBox.SetCurSel(0);
		CDiscRecorder *pdiscRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(0);
		OnCbnSelchangeDeviceCombo();  //***
	}
	IFileSystemImage  *ifs;
	HRESULT hRes=S_OK;
	if(pdiscRecorder!=NULL)
	{
		if (GetOSVersion() < WINDOWSVISTA)
			hRes=CoCreateInstance(__uuidof(MsftFileSystemImage),NULL,CLSCTX_ALL,__uuidof(IFileSystemImage ),(void**)&ifs);
		else
			hRes=CoCreateInstance(__uuidof(MsftFileSystemImage),NULL,CLSCTX_ALL,__uuidof(IFileSystemImage3),(void**)&ifs);
		if(SUCCEEDED(hRes))
		{
			hRes=ifs->get_UDFRevisionsSupported(&pVal);
			if(SUCCEEDED(hRes))
			{
				return pVal;
			}
			return 0;
		}
		else
		{
			return 0;
		}
	}
	else
	{
		return 0;
	}
	ifs->Release();
	return 0;
}

void CBurnCDDlg::FillUDFRevisionsCombo()
{
	int prev = m_UDFRevision.GetCurSel();
	m_UDFRevision.ResetContent();
	m_UDFRevision.AddString("Auto");
	if(b102)
		m_UDFRevision.AddString("V1.02");
	if(b150)
		m_UDFRevision.AddString("V1.50");
	if(b200) 
		m_UDFRevision.AddString("V2.00");
	if(b201) 
		m_UDFRevision.AddString("V2.01");
	if(b250) 
		m_UDFRevision.AddString("V2.50");
	if(b260)
		m_UDFRevision.AddString("V2.60");	
	if (prev < 0)
		prev = 0;
	m_UDFRevision.SetCurSel(prev);
}

void CBurnCDDlg::OnSelchangeComboUdfRev()
{
	UpdateData(TRUE);
	int index = m_UDFRevision.GetCurSel();
}

LONG CBurnCDDlg::GetUDFRevision()
{
	CString udfstr;
	int index = m_UDFRevision.GetCurSel();
	if (index == -1)
		return 0;
	m_UDFRevision.GetLBText(index, udfstr);
	if (udfstr == "Auto")
		return 0;
	if (udfstr == "V1.02")
		return 0x102;
	if (udfstr == "V1.50")
		return 0x150;
	if (udfstr == "V2.00")
		return 0x200;
	if (udfstr == "V2.01")
		return 0x201;
	if (udfstr == "V2.50")
		return 0x250;
	if (udfstr == "V2.60")
		return 0x260;
	return 0x102;
}


int CBurnCDDlg::GetFileSystem()
{
	int fsidx = m_FileSystemCombo.GetCurSel();
	switch (fsidx)
	{
		case 0:
			return FS_AUTO;					
		break;
		case 1:
			return FsiFileSystemISO9660;	
		break;
		case 2:
			return FsiFileSystemISO9660|FsiFileSystemJoliet;
		break;
		case 3:
			return FsiFileSystemISO9660|FsiFileSystemJoliet|FsiFileSystemUDF;
		break;
		case 4:
			return FsiFileSystemISO9660|FsiFileSystemUDF;
		break;
		case 5:
			return FsiFileSystemUDF;
		break;
		case 6:
			return FSi_AUDIOCD;
		break;
		case 7:
			return FSi_AUDIOCD_DAO;
		break;
	}
	return 0;
}

void CBurnCDDlg::OnSelchangeComboFilesystem()
{
	this->SendMessage(WM_UPDATEDATA, 0, 0); //we are doing it this way outside of a thread as a thread calls this function.
	int fsidx = m_FileSystemCombo.GetCurSel();
	switch (fsidx)
	{
		GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(TRUE);
		GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(TRUE);
		GetDlgItem(IDC_RADIOBURNISO)->EnableWindow(TRUE);
		GetDlgItem(IDC_CHECK_BOOTIMAGE)->EnableWindow(TRUE);

		GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
		GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
		GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(TRUE);
		GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(TRUE);
		case FS_AUTO:
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
		break;
		case FS_ISO9660:
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(FALSE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(FALSE);
		break;
		case FS_ISO9660_JOLIET:
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(FALSE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(FALSE);
		break;
		case FS_ISO9660_JOLIET_UDF:
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
		break;
		case FS_ISO9660_UDF:
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
		break;
		case FS_UDF:
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(TRUE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(TRUE);
		break;
		case FS_AUDIOCD:
		case FS_AUDIOCD_DAO:	
			GetDlgItem(IDC_STATICUDFREV)->EnableWindow(FALSE);
			GetDlgItem(IDC_COMBO_UDF_REV)->EnableWindow(FALSE);
			GetDlgItem(IDC_UPDATE_BUTTON)->EnableWindow(FALSE);
			GetDlgItem(IDC_CLOSE_MEDIA_CHK)->EnableWindow(FALSE);
			GetDlgItem(IDC_RADIOBURNISO)->EnableWindow(FALSE);
			GetDlgItem(IDC_CHECK_BOOTIMAGE)->EnableWindow(FALSE);
		break;
	}
}

#include "dbt.h"
LRESULT CBurnCDDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
		case WM_QUERYENDSESSION:
			if (m_nCurrentMode != PROGRAM_IDLE)
			{
				return FALSE;
			}
		break;
		case WM_POWERBROADCAST :
			if (m_nCurrentMode != PROGRAM_IDLE)
			{
				if (wParam == PBT_APMQUERYSUSPEND || wParam == PBT_APMSUSPEND)
				{
					return BROADCAST_QUERY_DENY ;
				}
			}
		break;
		case WM_DEVICECHANGE:
		{
			PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
			switch(wParam)
			{
				case DBT_DEVICEARRIVAL:
				{
					// See if a CD-ROM or DVD was inserted into a drive.
					if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
					{
						m_oversizequestion = false;
						PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
						if (lpdbv -> dbcv_flags & DBTF_MEDIA)
						{
							if (m_bWaitingForDisc)
							{
								StartNextCopy();
								return CDialog::WindowProc(message, wParam, lParam);
							}
							else if (m_nCurrentMode != PROGRAM_IDLE)
								return CDialog::WindowProc(message, wParam, lParam);
							else
							{
								ChangeDeviceCombo();
								//FillSpeedsComboBox();
								EnableBurnButton();
								GetVolumeName();
							}
						}
						else if (lpdbv -> dbcv_flags == 0)
						{
							if (m_nCurrentMode == PROGRAM_IDLE)
								AfxBeginThread(AddRecordersToComboBoxThread, this, THREAD_PRIORITY_NORMAL);						
						}
	
					}
				}
				break;
				case DBT_DEVICEREMOVECOMPLETE:
				// See if a CD-ROM was removed from a drive.
				if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
				{
					m_oversizequestion = false;
					PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
					if (lpdbv -> dbcv_flags & DBTF_MEDIA)
					{
						if (m_bWaitingForDisc || m_nCurrentMode != PROGRAM_IDLE)
								return CDialog::WindowProc(message, wParam, lParam);  // if waiting for disc insertion for another copy ignore ejects
						char drive = FirstDriveFromMask(lpdbv ->dbcv_unitmask);
						ChangeDeviceCombo();	
						m_maxText.SetWindowTextA("0.0GB");
						m_TotalSizeText.SetWindowText("");
						m_capacityProgress.SetPos(0);
						m_progressCtrl.SetRange32(0, 100);
						m_progressCtrl.SetPos(0);
						EnableBurnButton();
					}
					if (lpdbv -> dbcv_flags == 0)
					{
						if (m_nCurrentMode == PROGRAM_IDLE)
							AfxBeginThread(AddRecordersToComboBoxThread, this, THREAD_PRIORITY_NORMAL);
					}
				}
				break;
			}
		}
	}
	return CDialog::WindowProc(message, wParam, lParam);
}

/*----------------------------------------------------------------------
FirstDriveFromMask (unitmask)

Finds the first valid drive letter from a mask of drive letters. The
mask must be in the format bit 0 = A, bit 1 = B, bit 3 = C, etc.

A valid drive letter is defined when the corresponding bit is set to 1.

Returns the drive letter that was first found.
----------------------------------------------------------------------*/ 
char CBurnCDDlg::FirstDriveFromMask (ULONG unitmask)
{
	char i;
	for (i = 0; i < 26; ++i)
	{
		if (unitmask & 0x1)
			break;
		unitmask = unitmask >> 1;
	}
	return (i + 'A');
} 

#include "globals.h"
void CBurnCDDlg::OnClose()
{
	if (m_nCurrentMode != PROGRAM_IDLE)
	{
		if (MessageBox("You should not close the program while the burner is active, you may destroy the disc.  Are you sure you want to close?", "Are You Sure?", MB_ICONQUESTION|MB_YESNO) == IDNO)
		return;
	}
	if (m_addingdrives)
	{	
		MessageBox("The program cannot close while initializing drives.  Please wait a few seconds and then try again.", "Cannot Close", MB_ICONSTOP|MB_OK);
		return;
	}
	CString str;
	int sel = m_deviceComboBox.GetCurSel();
	m_deviceComboBox.GetLBText(sel, str);
	str.Delete(0, 2);
	WriteString("Last Selected Drive", str);
	WriteInt("EjectWhenFinished", m_ejectWhenFinished.GetCheck());
	FREETOOL(IDC_ADD_FILES_BUTTON));
	FREETOOL(IDC_UPDATE_BUTTON));
	FREETOOL(IDC_REMOVE_FILES_BUTTON));
	FREETOOL(IDC_BUTTON_REMOVEALL));
	FREETOOL(IDC_DEVICE_COMBO));
	FREETOOL(IDC_BURN_FILE_LIST));
	FREETOOL(IDC_VOLUME));
	FREETOOL(IDC_CLOSE_MEDIA_CHK));
	FREETOOL(IDC_RADIOBURNFILES));
	FREETOOL(IDC_RADIOBURNISO));
	FREETOOL(IDC_BURN_BUTTON));
	FREETOOL(IDC_ERASE));
	FREETOOL(IDC_BUTTON_EJECT));
	FREETOOL(IDC_COMBO_UDF_REV));
	FREETOOL(IDC_COMBO_MEDIA_SPEEDS));
	FREETOOL(IDC_CHECK_BURNPROOF));
	FREETOOL(IDC_COMBO_FILESYSTEM));
	FREETOOL(IDC_EJECT_WHEN_FINISHED));
	FREETOOL(IDC_CHECK_MULTISESSION));
	FREETOOL(IDC_CHECK_BOOTIMAGE));
	FREETOOL(IDC_BUTTON_SAVE));
	FREETOOL(IDC_BUTTON_LOAD));
	FREETOOL(IDC_BUTTON_UP));
	FREETOOL(IDC_BUTTON_DOWN));
	FREETOOL(IDC_BUTTON_WIZARD));
	FREETOOL(IDC_ISODISC));
	FREETOOL(IDC_EDIT_NUMCOPIES));
	FREETOOL(IDC_SPIN2));
	FREETOOL(IDC_CHECK_USECAV));
	FREETOOL(IDC_BUTTON_SAVEIBG));
	int itemCount = m_fileListbox.GetCount();
	for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
	{
		delete (CBaseObject*)m_fileListbox.GetItemDataPtr(itemIndex);
	}
	itemCount = m_deviceComboBox.GetCount();
	for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
	{
		delete (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(itemIndex);
	}
	::CoUninitialize();
	RemoveTrayIcon();
	if (m_pTaskbarList)
	{
		m_pTaskbarList->Release();
		m_pTaskbarList = NULL;
	}
	CDialog::OnClose();
}

void CBurnCDDlg::SetLastSelectedDrive()
{
	CString str, str1;
	str = GetString("Last Selected Drive", "");
	if (str.GetLength() == 0)
		m_deviceComboBox.SetCurSel(0);
	else
	{
		for (int i=0; i< m_deviceComboBox.GetCount(); i++)
		{
			m_deviceComboBox.GetLBText(i, str1);
			str1.Delete(0, 2);	
			if (str == str1)
			{
				m_deviceComboBox.SetCurSel(i);
				return;
			}
		}
	}
	m_deviceComboBox.SetCurSel(0);
}

void CBurnCDDlg::SelectDriveFromArgument(CString* str)
{
	CString str1;
	for (int i=0; i< m_deviceComboBox.GetCount(); i++)
	{
		m_deviceComboBox.GetLBText(i, str1);
		int loc = str1.Find(':', 0);
		CString tmp;
		tmp = str1.GetAt(loc-1);
		tmp += ":";
		if (str->Left(2) == tmp)
		{
			m_deviceComboBox.SetCurSel(i);
			return;
		}
	}
	m_deviceComboBox.SetCurSel(0);
}

void CBurnCDDlg::OnClickedButtonEject()
{
	EjectDrive();
	return;
}

#include "About.h"
void CBurnCDDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAbout dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

void CBurnCDDlg::OnClickedEjectWhenFinished()
{
	UpdateData(TRUE);
}

BOOL CBurnCDDlg::PreTranslateMessage(MSG* pMsg)
{
	m_pToolTip.RelayEvent(pMsg);
	return CDialog::PreTranslateMessage(pMsg);
}

void CBurnCDDlg::OnClickedCloseMediaChk()
{
	UpdateData(TRUE);
}

void CBurnCDDlg::OnClickedCheckMultisession()
{
	UpdateData(TRUE);
}

void CBurnCDDlg::OnClickedCheckShutdownwhencomplete()
{
	UpdateData(TRUE);
}

void CBurnCDDlg::ShutDownWindows()
{
	HANDLE hToken; // handle to process token 
	TOKEN_PRIVILEGES tkp; // pointer to token structure
	OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); // Get the LUID for shutdown privilege.
	LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 
	tkp.PrivilegeCount = 1; // one privilege to set
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;   // Get shutdown privilege for this process. 
	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);// Cannot test the return value of AdjustTokenPrivileges.if (GetLastError() != ERROR_SUCCESS)   
	ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE|EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED);

}

#include "comutil.h"
#include "BootOptions.h"
void CBurnCDDlg::OnClickedCheckBootimage()
{
	UpdateData(TRUE);
	CBootOptions dlg;
	IBootOptions*			pBootOptions = NULL;
	IStream*				bootStream = NULL;
	if (m_bMulti.GetCheck() == BST_CHECKED)
	{
		MessageBox("Error,  you cannot make a multisession disc bootable", "Error", MB_ICONSTOP);
		m_CheckBootable.SetCheck(BST_UNCHECKED);
		m_cBootFileName.Empty();
		m_BootImageFile = "";
	}
	if (m_CheckBootable.GetCheck() == BST_CHECKED)
	{
		OPENFILENAME	m_ofn;
		GetFiles(m_hWnd, &m_ofn, "Select a bootable image file (*.ima, *.bin)", NULL, TEXT(_T("Boot Files (*.ima, *.bin)\0*.ima;*.bin\0All Files (*.*)\0*.*\0\0")), _T("BOOTIMAGES"), 
					 m_cBootFileName.GetBuffer(MAX_PATH), MAX_PATH, NULL, 0, OFN_FILEMUSTEXIST+OFN_EXPLORER, "IMA");
		HRESULT hRes, hRes1, hRes2, hRes3;
		pBootOptions = NULL;
		hRes = CoCreateInstance(CLSID_BootOptions, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pBootOptions));
		if (FAILED(hRes))
			return;
		if (SUCCEEDED(hRes))
		{	
			if (m_cBootFileName != "")
			{
				
				USES_CONVERSION;
				CString bootW;
				bootW.Format("\\\\?\\%s", bootW);
				hRes = SHCreateStreamOnFileW(A2CW(m_cBootFileName), STGM_READ | STGM_SHARE_DENY_WRITE, &bootStream);
				if (FAILED(hRes))
				{
					return;
				}
				if (SUCCEEDED(hRes))
				{
					BSTR manu;
					PlatformId platform;
					EmulationType emulation;
					ULONG imagesize;
					hRes = pBootOptions->get_Manufacturer(&manu);
					hRes1 = pBootOptions->get_PlatformId(&platform);
					hRes2 = pBootOptions->get_Emulation(&emulation);
					hRes3 = pBootOptions->get_ImageSize(&imagesize);
					_bstr_t bstrIntermediate(manu);
					dlg.manustr.Format(_T("%s"),(LPCTSTR)bstrIntermediate);
					dlg.nPlatform = platform;
					dlg.nEmulation = emulation;
					dlg.m_nImageSize = imagesize;
					if (dlg.DoModal() == 1)
					{
						manu = dlg.manustr.AllocSysString();
						hRes1 = pBootOptions->put_Manufacturer(manu);
						hRes2 = pBootOptions->put_PlatformId((PlatformId)dlg.nPlatform);
						hRes3 = pBootOptions->put_Emulation((EmulationType)dlg.nEmulation);
						pBootOptions->Release();
						if (SUCCEEDED(hRes1) && SUCCEEDED(hRes2) && SUCCEEDED(hRes3))
							MessageBox("Boot options successfully changed");
						else if (FAILED(hRes1) && FAILED(hRes2) && FAILED(hRes3))
							MessageBox("Changing Boot options failed. defaults used");
					}
				}
			}	
		}
		m_BootImageFile = m_cBootFileName;
	}
	else
		m_cBootFileName.Empty();

}

void CBurnCDDlg::OnClickedButtonSave()
{
	if (m_fileListbox.GetCount() == 0)
	{
		MessageBox("There are no items in the list box to save", "No Entries", MB_ICONSTOP);
		return;
	}
	_TCHAR currdir[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, currdir);  //Save current directory
	SetCurrentDirectory(currdir);
	CString filename;
	CFileDialog fileDialog(FALSE, "dpb", NULL, NULL, _T("DPB File (*.dpb)|*.dpb|ImgBurn Project File (*.ibb)|*.ibb||"), NULL, 0);
	fileDialog.GetOFN().lpstrInitialDir = GetString("LastSaveListDir", "");
	fileDialog.GetOFN().lpstrTitle = "Choose a path and filename to save as";
	if (fileDialog.DoModal() == IDOK)
	{
		CFileObject* pFileObject = new CFileObject(fileDialog.GetPathName());
		filename = pFileObject->GetPath();
		delete pFileObject;
	}
	int findIndex = filename.ReverseFind(_T('\\'));
	CString path = filename.Left(findIndex+1);
	WriteString("LastAddFilesDir", path);
	
	if (filename.Right(4) == ".IBB")
	{
		SaveIBBFile(&filename);
		SetWaitCursor(FALSE);
		return;
	}
	CFile theFile;
	if (theFile.Open(filename, CFile::modeWrite|CFile::modeCreate) == 0)
	{
		MessageBox("Error opening file for writing", "Access error", MB_ICONSTOP);
		return;
	}
	CArchive archive(&theFile, CArchive::store);
	int version = PROJECT_VERSION_SUPPORTED;
	filename = "DPB";
	archive << filename;
	archive << version;
	archive << m_fileListbox.GetCount();
	CString tmpstr;
	CBaseObject* pObject;
	SetWaitCursor(TRUE);
	for (int i=0; i < m_fileListbox.GetCount(); i++)
	{
		 
		pObject = (CBaseObject*)m_fileListbox.GetItemDataPtr(i);
		ASSERT(pObject != NULL);
		if (pObject == NULL)
		continue;
		CString fileName = pObject->GetPath();
		archive.WriteString(fileName.GetBuffer(0));
		archive.WriteString(_T("\n"));
	}
	SetWaitCursor(FALSE);
	archive.Close();
	theFile.Close();
}

void CBurnCDDlg::OnClickedButtonLoad()
{
	CString filename;
	CFileDialog fileDialog(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, _T("DPB Files (*.dpb)|*.dpb||"), NULL, 0);
	fileDialog.GetOFN().lpstrTitle = "Select a project file to load";
	if (fileDialog.DoModal() == IDOK)
	{
		CFileObject* pFileObject = new CFileObject(fileDialog.GetPathName());
		filename = pFileObject->GetPath();
		delete pFileObject;
	}
	else return;
	CFile theFile;
	int itemCount = m_fileListbox.GetCount();
	for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
	{
		CBaseObject *obj = (CBaseObject*)m_fileListbox.GetItemDataPtr(itemIndex);
		if (obj)
			delete obj; 
		   
	}
	m_fileListbox.ResetContent();
	if (theFile.Open(filename.GetBuffer(0), CFile::modeRead) == 0)
	{
		MessageBox("Error opening requested file for reading", "Error opening", MB_ICONSTOP);
		return;
	}
	CArchive archive(&theFile, CArchive::load);
	int version=0,iItemCount=0;
	CString tmp="";
	archive >> tmp;
	if (tmp != "DPB")
	{
		MessageBox("This file is not a supported project file", "Wrong File", MB_ICONSTOP);
		return;
	}
	archive >> version;
	if (version != 1)
	{
		MessageBox("This file is recognised but an unsupported version", "Version un-supported", MB_ICONSTOP);
		return;
	}
	archive >> iItemCount;
	if (iItemCount == 0)
	{
		MessageBox("This file has no item entries", "No Entries", MB_ICONSTOP);
		return;
	}
	CString cItem;
	SetWaitCursor(TRUE);
	int i;
	for (i=0; i < iItemCount; i++)
	{
		archive.ReadString(cItem);
		if (isDirectory(cItem))
		{
			CDirObject* pDirObject = new CDirObject(cItem);
			int addIndex = m_fileListbox.AddString(pDirObject->GetName());
			m_fileListbox.SetItemDataPtr(addIndex, pDirObject);
		}
		else
		{
			CFileObject* pFileObject = new CFileObject(cItem);
			int addIndex = m_fileListbox.AddString(pFileObject->GetName());
			m_fileListbox.SetItemDataPtr(addIndex, pFileObject);
		}
	}
	SetWaitCursor(FALSE);
	archive.Close();
	theFile.Close();
	if (i==0)
		UpdateCapacity();
	else
		UpdateCapacity(TRUE);
	EnableBurnButton();
}

void CBurnCDDlg::SaveIBBFile(CString *cFileName)
{
	CFile theFile;
	CString tmp;
	if (theFile.Open(cFileName->GetBuffer(0), CFile::modeWrite|CFile::modeCreate|CFile::shareDenyNone) == 0)
	{
		MessageBox("Error,  could not open the file for writing. Check permissions", "Access error", MB_ICONSTOP);
		return;
	}
		SetWaitCursor(TRUE);
	theFile.Write("IBB\r\n\r\n", 5);
	theFile.Write("[START_BACKUP_OPTIONS]\r\n", 23);
	theFile.Write("BuildInputMode=",15);
	theFile.Write("1\r\n", 2);
	theFile.Write("BuildOutputMode=",16);
	theFile.Write("1\r\n", 2);
	theFile.Write("Destination=",12);
	theFile.Write("0\r\n", 2);
	theFile.Write("TestMode=",9);
	theFile.Write("0\r\n", 2);
	theFile.Write("Verify=",7);
	theFile.Write("0\r\n", 2);
	theFile.Write("WriteSpeed=",11);
	theFile.Write("0\r\n", 2);
	theFile.Write("Copies=",7);
	theFile.Write("0\r\n", 2);
	theFile.Write("DataType=",9);
	theFile.Write("0\r\n", 2);
	theFile.Write("FileSystem=",11);
	theFile.Write("1\r\n", 2);
	theFile.Write("UDFRevision=",12);
	theFile.Write("4\r\n", 2);
	theFile.Write("PreserveFullPathnames=",22);
	theFile.Write("0\r\n", 2);
	theFile.Write("RecurseSubdirectories=",22);
	theFile.Write("1\r\n", 2);
	theFile.Write("IncludeHiddenFiles=",19);
	theFile.Write("0\r\n", 2);
	theFile.Write("IncludeSystemFiles=",19);
	theFile.Write("0\r\n", 2);
	theFile.Write("IncludeArchiveFilesOnly=",24);
	theFile.Write("0\r\n", 2);
	theFile.Write("AddToWriteQueueWhenDone=",24);
	theFile.Write("0\r\n", 2);
	theFile.Write("ClearArchiveAttribute=",22);
	theFile.Write("0\r\n", 2);
	theFile.Write("VolumeLabel_ISO9660=",20);
	theFile.Write(m_volumeLabel.GetBuffer(0), m_volumeLabel.GetLength());
	theFile.Write("\r\n", 1);
	theFile.Write("VolumeLabel_Joliet=",19);
	theFile.Write(m_volumeLabel.GetBuffer(0), m_volumeLabel.GetLength());
	theFile.Write("\r\n", 1);
	theFile.Write("VolumeLabel_UDF=",16);
	theFile.Write(m_volumeLabel.GetBuffer(0), m_volumeLabel.GetLength());
	theFile.Write("\r\n", 1);
	theFile.Write("Identifier_System=\r\n",19);
	theFile.Write("Identifier_VolumeSet=\r\n",22);
	theFile.Write("Identifier_Publisher=\r\n",22);
	theFile.Write("Identifier_Preparer=\r\n",21);
	theFile.Write("Identifier_Application=\r\n",24);
	theFile.Write("Dates_FolderFileType=",21);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_InterchangeLevel=",38);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_CharacterSet=",34);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_AllowMoreThan8DirectoryLevels=",50);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_AllowMoreThan255CharactersInPath=",53);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_AllowFilesWithoutExtensions=",49);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_AllowFilesExceedingSizeLimit=",50);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_ISO9660_DontAddVersionNumberToFiles=",49);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_Joliet_InterchangeLevel=",37);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_Joliet_AllowFilesWithoutExtensions=",48);
	theFile.Write("1\r\n", 2);
	theFile.Write("Restrictions_Joliet_AddVersionNumberToFiles=",43);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_DisableUnicodeSupport=",38);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_DVDVideoDontDisableUnicodeSupport=",49);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_DVDVideoDontDisableUnicodeSupport_SF=",52);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_HDDVDVideoDontDisableUnicodeSupport=",51);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_HDDVDVideoDontDisableUnicodeSupport_SF=",53);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_BDVideoDontDisableUnicodeSupport=",50);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_BDVideoDontDisableUnicodeSupport_SF=",53);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_DVDVideoAllowUnicodeVolumeLabel=",49);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_HDDVDVideoAllowUnicodeVolumeLabel=",51);
	theFile.Write("0\r\n", 2);
	theFile.Write("Restrictions_UDF_BDVideoAllowUnicodeVolumeLabel=",48);
	theFile.Write("0\r\n", 2);
	theFile.Write("BootableDisc_MakeImageBootable=", 31);
	tmp.Format("%d", m_CheckBootable.GetCheck());
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	theFile.Write("\r\n",	1);
	theFile.Write("BootableDisc_MediaEmulationType=",32);
	theFile.Write("0\r\n", 2);
	theFile.Write("BootableDisc_BootImageFile=", 27);
	theFile.Write(m_BootImageFile.GetBuffer(0), m_BootImageFile.GetLength());
	theFile.Write("\r\n",	1);
	theFile.Write("BootableDisc_DeveloperIdentifier=",33);
	theFile.Write("\r\n",	1);
	theFile.Write("BootableDisc_LoadSegment=",25);
	theFile.Write("07C0\r\n", 5);
	theFile.Write("BootableDisc_LoadSectorCount=",29);
	theFile.Write("4", 1);
	theFile.Write("\r\n",	1);
	theFile.Write("[END_BACKUP_OPTIONS]\r\n", 22);
	theFile.Write("\r\n",	1);
	theFile.Write("[START_BACKUP_LIST]\r\n", 20);
	CString tmpstr;
	CBaseObject* pObject;
	for (int i=0; i < m_fileListbox.GetCount(); i++)
	{
		pObject = (CBaseObject*)m_fileListbox.GetItemDataPtr(i);
		ASSERT(pObject != NULL);
		if (pObject == NULL)
			continue;
		CString fileName = pObject->GetPath();
		if (isDirectory(fileName))
		{
			theFile.Write(fileName.GetBuffer(0), fileName.GetLength());
			theFile.Write("\\", 1);
			theFile.Write("\r\n",1);
		}
		else
		{
			theFile.Write(fileName.GetBuffer(0), fileName.GetLength());
			theFile.Write("\r\n",1);
		}
	}
	theFile.Write("[END_BACKUP_LIST]\r\n", 18);
	SetWaitCursor(FALSE);
	theFile.Close();
}

#include "htmlhelp.h"
void CBurnCDDlg::OnClickedHelpbutton()
{
	_TCHAR  sProgramDir[MAX_PATH_UNICODE], drive[_MAX_DRIVE];				
	_TCHAR dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
	_tsplitpath_s((_TCHAR *)AfxGetApp()->m_pszHelpFilePath, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT );
	CString tmp = _T("MagicBurner.chm::/MagicBurner.htm");
	_tmakepath_s(sProgramDir, MAX_PATH_UNICODE, drive, dir, tmp, NULL);
	HWND hwnd = ::HtmlHelp(GetDesktopWindow()->m_hWnd, sProgramDir, HH_DISPLAY_TOPIC, NULL) ;
}


// Get a disc recorder given a disc index
HRESULT CBurnCDDlg::GetDiscRecorder(ULONG index, IDiscRecorder2 ** recorder)
{
	::CoInitializeEx(NULL, COINIT_MULTITHREADED);//
	HRESULT hr = S_OK;
	IDiscMaster2* tmpDiscMaster = NULL;
	BSTR tmpUniqueId;
	IDiscRecorder2* tmpRecorder = NULL;
	*recorder = NULL;
	// create the disc master object
	if (SUCCEEDED(hr))
	{
		hr = CoCreateInstance(CLSID_MsftDiscMaster2, NULL, CLSCTX_ALL, IID_PPV_ARGS(&tmpDiscMaster));
		if (FAILED(hr))
		{
			SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed CoCreateInstance"));
		 }
	}
	// get the unique id string
	if (SUCCEEDED(hr))
	{        
		hr = tmpDiscMaster->get_Item(index, &tmpUniqueId);
		if (FAILED(hr))
		{
		   SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed tmpDiscMaster->get_Item\n"));
		}
	}
	// Create a new IDiscRecorder2
	if (SUCCEEDED(hr))
	{
		hr = CoCreateInstance(CLSID_MsftDiscRecorder2, NULL, CLSCTX_ALL, IID_PPV_ARGS(&tmpRecorder));
		if (FAILED(hr))
		{
			SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed CoCreateInstance\n"));
		}
	}
	// Initialize it with the provided BSTR
	if (SUCCEEDED(hr))
	{
		hr = tmpRecorder->InitializeDiscRecorder(tmpUniqueId);
		if (FAILED(hr))
		{
		   SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)_T("Failed to init disc recorder\n"));
		}
	}
	// copy to caller or release recorder
	if (SUCCEEDED(hr))
	{
		*recorder = tmpRecorder;
	}
	else
	{
		ReleaseAndNull(tmpRecorder);
	}
	// all other cleanup
	ReleaseAndNull(tmpDiscMaster);
	FreeSysStringAndNull(tmpUniqueId);
	::CoUninitialize();
	return hr;
}


void CBurnCDDlg::OnClickedButtonSaveibg()
{
	SaveGraphData();
}

void CBurnCDDlg::SaveGraphData()
{
	iSpeedVector = SpeedVector.begin();
	iSectorVector = SectorVector.begin();
	iRateVector = RateVector.begin();
	iBufferVector = BufferVector.begin();
	iCPUVector = CPUVector.begin();
	
	_TCHAR currdir[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, currdir);  //Save current directory
	SetCurrentDirectory(currdir);
	CString filename;
	CFileDialog fileDialog(FALSE, "ibg", NULL, NULL, _T("IBG Graph File (*.ibg)|*.ibg| MagicBurner Graph File (*.mbg)|*.mbg||"), NULL, 0);
	fileDialog.GetOFN().lpstrInitialDir = GetString("LastSaveIbgDir", "");
	fileDialog.GetOFN().lpstrTitle = "Choose a path/filename & type to save Graph file as";
	if (fileDialog.DoModal() == IDOK)
	{
		CFileObject* pFileObject = new CFileObject(fileDialog.GetPathName());
		filename = pFileObject->GetPath();
		delete pFileObject;
	}
	else
		return;
	int findIndex = filename.ReverseFind(_T('\\'));
	CString path = filename.Left(findIndex+1);
	WriteString("LastSaveIbgDir", path);
	CFile theFile;
	if (theFile.Open(filename, CFile::modeWrite|CFile::modeCreate) == 0)
	{
		MessageBox("Error opening file for writing", "Access error", MB_ICONSTOP);
		return;
	}
	float spdvec, cpuvec;
	long secvec, ratevec, buffvec;
	CString tmp;
	tmp = "IBGD\r\n\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	tmp = "[START_CONFIGURATION]\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	tmp = "IBGD_VERSION=2\r\n\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());

	char timebuf[50];
	time_t today = time(NULL);
	tm tm_time; // = *localtime(&today);
	int error = _localtime32_s(&tm_time, (__time32_t*) &today);
	strftime(timebuf, 50, "%#c\r\n\r\n", &tm_time);
	//DATE=24/10/2007 13:58:39
	tmp = "DATE=";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	tmp = timebuf;
	int pos = tmp.Find(',', 0);
	tmp.Delete(0, pos+1);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());

	//SAMPLE_RATE=100
	tmp = "SAMPLE_RATE=100\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	
	//DEVICE=[4:0:0] TSSTcorp CDDVDW SH-S203B SB01 (M:) (ATA)
	tmp = "DEVICE=";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());

	int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
	CDiscRecorder* pOrigDiscRecorder = (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
	int legacy;
	CString vendorId;
	CString productId;
	CString productrev;
	CString volumeList;	
	if (pOrigDiscRecorder != NULL)
	{
		// Get the volume path(s). usually just 1
		ULONG totalVolumePaths = pOrigDiscRecorder->GetTotalVolumePaths();
		for (ULONG volIndex = 0; volIndex < totalVolumePaths; volIndex++)
		{
			if (volIndex)
				volumeList += _T(",");
			volumeList += pOrigDiscRecorder->GetVolumePath(volIndex);
		}
		// Add Drive to combo and IDiscRecorder as data
		legacy = pOrigDiscRecorder->GetLegacyDeviceNumber();
		vendorId = pOrigDiscRecorder->GetVendorId();
		productId = pOrigDiscRecorder->GetProductID();
		productrev = pOrigDiscRecorder->GetProductRevision();
		tmp.Format(_T("%d (%s:) %s %s (%s)\r\n"), legacy, (LPCTSTR)volumeList, (LPCTSTR)vendorId, (LPCTSTR)productId, (LPCTSTR)productrev);
		theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	}
	else
	{
		tmp = "\r\n";
		theFile.Write(tmp.GetBuffer(0), tmp.GetLength());

	}
	//DEVICE_ADDRESS=4:0:0
	tmp.Format("DEVICE=%d:0:0\r\n", legacy);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DEVICE_MAKEMODEL=TSSTcorp CDDVDW SH-S203B
	tmp.Format("DEVICE_MAKEMODEL=%s%s\r\n", (LPCTSTR)vendorId, (LPCTSTR)productId);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DEVICE_FIRMWAREVERSION=SB0
	tmp.Format("DEVICE_FIRMWAREVERSION=%s\r\n", (LPCTSTR)productrev);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DEVICE_DRIVELETTER
	tmp.Format("DEVICE_DRIVELETTER=%s\r\n", (LPCTSTR)volumeList);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DEVICE_BUSTYPE=ATA
	tmp = "DEVICE_BUSTYPE=\r\n\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	
	//MEDIA_TYPE=DVD+RW
	IMAPI_MEDIA_PHYSICAL_TYPE type = m_mediatype;
	tmp.Format("MEDIA_TYPE=%s\r\n", m_cmediatype);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
				
	//MEDIA_BOOKTYPE=DVD-ROM
	tmp.Format("MEDIA_BOOKTYPE=%s\r\n", "N/S");
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//MEDIA_ID=MKM-A03-00
	//CString midcode = "";
	//GetMediaMidCode(&midcode);
	//if (m_midcode.GetLength() > 0)
	//{
		tmp.Format("MEDIA_ID=%s\r\n", m_midcode);
		theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//}
	//else
	//{
	//	tmp.Format("MEDIA_ID=%s\r\n", "N/A");
	//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//}
	//MEDIA_TRACKPATH=PTP
	tmp.Format("MEDIA_TRACKPATH=\r\n", "N/S");
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//MEDIA_SPEEDS=4x, 6x, 8x
	//m_MediaSpeeds.GetLBText(1, MaxSpeed);
	tmp.Format("MEDIA_SPEEDS=%s\r\n", m_MaxSpeed);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//MEDIA_CAPACITY=2295104
	tmp.Format("MEDIA_CAPACITY=%d\r\n", (LONG)m_MediaCapacity);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//MEDIA_LAYER_BREAK=0
	tmp.Format("MEDIA_LAYER_BREAK=%d\r\n\r\n", m_LayerBreak);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	
	//DATA_IMAGEFILE=-==/\/[DISCOVERY IMAGE]\/\==-
	tmp.Format("DATA_IMAGEFILE=%s\r\n", 0);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DATA_SECTORS=2295104
	tmp.Format("DATA_SECTORS=%d\r\n", (LONG)m_datasectors);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DATA_TYPE=MODE1/2048
	tmp.Format("DATA_TYPE=%s\r\n", "MagicBurner");
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//DATA_VOLUMEIDENTIFIER=DISCOVERY_IMAGE
	//CString vol = "";
	//GetVolumeName(&vol);
	tmp.Format("DATA_VOLUMEIDENTIFIER=%s\r\n\r\n", m_volumeLabel.GetBuffer(0));
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	
	//WRITE_TEST_MODE=False
	tmp.Format("WRITE_TEST_MODE=%s\r\n", "N/S");
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//WRITE_SPEED_SELECTED=MAX
	tmp.Format("WRITE_SPEED_SELECTED=%s\r\n", m_SelectedSpeed);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//WRITE_SPEED_START=6.15
	tmp.Format("WRITE_SPEED_START=%4.1f\r\n", *iSpeedVector);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//WRITE_SPEED_END=8.04
	iSpeedVector = SpeedVector.end() - 1;
	tmp.Format("WRITE_SPEED_END=%4.1f\r\n", *iSpeedVector);  
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//WRITE_SPEED_AVERAGE=7.45
	int count = 0;
	float val = 0, maxv = 0;
	for (iSpeedVector = SpeedVector.begin(); iSpeedVector < SpeedVector.end();)
	{
		float sv = *iSpeedVector++;
		val += sv;
		if ( sv > maxv)
			maxv = sv;
		count++;
	}
	tmp.Format("WRITE_SPEED_AVERAGE=%4.1f\r\n",  (float)(val/count));
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//WRITE_SPEED_MAX=8.06
	tmp.Format("WRITE_SPEED_MAX=%4.1f\r\n", maxv);
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//WRITE_TIME_TAKEN=453
	tmp.Format("WRITE_TIME_TAKEN=%01d:%02d:%02d\r\n\r\n", m_ElapsedTime.GetHours(), m_ElapsedTime.GetMinutes(), m_ElapsedTime.GetSeconds());
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	
	iSpeedVector = SpeedVector.begin(); 
//	//VERIFY_SPEED_START=2.84
//	tmp.Format("VERIFY_SPEED_START=%d\r\n", 0);
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	//VERIFY_SPEED_END=12.09
//	tmp.Format("VERIFY_SPEED_END=%d\r\n", 0);
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	//VERIFY_SPEED_AVERAGE=7.45
//	tmp.Format("VERIFY_SPEED_AVERAGE=%d\r\n", 0);
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	//VERIFY_SPEED_MAX=12.09
//	tmp.Format("VERIFY_SPEED_MAX=%d\r\n", 0);
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	//VERIFY_TIME_TAKEN=445
//	tmp.Format("VERIFY_TIME_TAKEN=%d\r\n\r\n", 0);
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	//[END_CONFIGURATION]
	tmp = "[END_CONFIGURATION]\r\n\r\n", 0;
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	//HRPC=True
	tmp.Format("HRPC=%s\r\n\r\n", "");
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	
	tmp = "[START_WRITE_GRAPH_VALUES]\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	for (; iSpeedVector < SpeedVector.end();)
	{
		spdvec = *iSpeedVector++;
		secvec = *iSectorVector++;
		ratevec = *iRateVector++;
		buffvec = *iBufferVector++;
		cpuvec = *iCPUVector++;
		
		tmp.Format("%4.2f,%d,%d,%d,%4.2f\r\n", spdvec, secvec, ratevec, buffvec, cpuvec );
		theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	}
	tmp = "[END_WRITE_GRAPH_VALUES]\r\n", 0;
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	tmp = "[START_VERIFY_GRAPH_VALUES]\r\n", 0;
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
//	
//	tmp = "[END_VERIFY_GRAPH_VALUES]\r\n", 0;
//	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	theFile.Close();
	if (theFile.Open(filename, CFile::modeReadWrite) == 0)
		return;
	UINT len = (UINT) theFile.GetLength();
	UCHAR *buffer;
	buffer = new UCHAR[len + 1];
	int FileLength = len;
	theFile.Read(buffer, len);
	CString CRCout = GraphData_CalculateCRC(buffer,  len);
	theFile.SeekToEnd();
	theFile.Write(CRCout.GetBuffer(0), CRCout.GetLength());
	tmp = "\r\n";
	theFile.Write(tmp.GetBuffer(0), tmp.GetLength());
	theFile.Close();
	delete [] buffer;
}

static DWORD CRC_Table[256] = {
  0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
  0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
  0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
  0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
  0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
  0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
  0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
  0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
  0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
  0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
  0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
  0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
  0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
  0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
  0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
  0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
  0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
  0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
  0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
  0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
  0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
  0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
  0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
  0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
  0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
  0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
  0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
  0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
  0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
  0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
  0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
  0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
  0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
  0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
  0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
  0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
  0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
  0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
  0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
  0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
  0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
  0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
  0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
  0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
  0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
  0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
  0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
  0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
  0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
  0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
  0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
  0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
  0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
  0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
 
// ----------------------------------------------------------------------------------------------
 
DWORD CBurnCDDlg::CalculateCRC(UCHAR *Buffer, DWORD Length)
{
   DWORD CRC = 0xFFFFFFFF;
   DWORD i;
 
   for(i = 0; i < Length; i++)
   {
	 CRC = ((CRC >> 8) ^ CRC_Table[(CRC & 0xFF) ^ Buffer[i]]);
   }
 
   return (CRC ^ 0xFFFFFFFF);
}
// ----------------------------------------------------------------------------------------------
CString CBurnCDDlg::GraphData_CalculateCRC(UCHAR *buffer,  int len)
{
	CString Temp,AnsiCRC;
	char Temp2[2];
	DWORD CRC = 0;
	BYTE HexByte;
	UCHAR ch, ch1;
	Temp.Empty();
	AnsiCRC.Empty();
	memset(Temp2, 0, 2);
	bool finish = false;
	int i;
	for(i = 0; i < len;)
	{
		do
		{
			ch = buffer[i++];(ch != '\n' && ch != '\r');
			ch1 = buffer[i];
			if (i > (len - 200) && ch == 'S' && ch1 == ']')
			{
				Temp += ch;
				Temp += ch1;
				finish = true;
				break;
			}
			else if (ch != '\n' && ch != '\r')
				Temp += ch;
		}while(ch != '\n' && ch != '\r');
		do
		{
			ch = buffer[i++];
		}
		while(ch == '\n' || ch == '\r');
		i -= 1;
		// Loop all the lines in the file - excluding the CRC line of course!
		if(Temp.GetLength())
		{
			CRC += CalculateCRC((UCHAR *)Temp.GetBuffer(Temp.GetLength()), Temp.GetLength());
			Temp.ReleaseBuffer();
		}
		Temp.Empty();
		if (finish)
			i = len;
	}
  // Converts the DWORD to a string - making sure to show at least 8 chars. i.e. DWORD value of 1 = string of "00000001", not just "1". 
  Temp.Format("%08.X", CRC);
  for (int s = 0; s < 8; s++)
  {
	  if (Temp.GetAt(s) == ' ')
		  Temp.SetAt(s, '0');
  }
  for(i = 0; i < 8; i++)
  {
		Temp2[0] = Temp.GetAt(i);
		// Append single character hex string to output string (AnsiCRC is output string)
		AnsiCRC += Temp2[0];
		// Converts string value 0, 1, 2....E, F to byte value 0, 1, 2....14, 15
		HexByte =  (BYTE)axtoi(Temp2);
		HexByte ^= (BYTE)0xF;
		// Convert byte value to string value and append that string to the output string
		char a[2];
		_itoa_s(HexByte, a, 2, 16);
		AnsiCRC += a;
	}
  AnsiCRC.MakeUpper();
	return AnsiCRC;
}

//Function to convert a hexadecimal string to an integer.
int CBurnCDDlg::axtoi(const TCHAR *value)
{
  CString val;
  val.Empty();
  val = value;
  struct CHexMap
  {
	TCHAR chr;
	int value;
  };
  const int HexMapL = 16;
  CHexMap HexMap[HexMapL] =
  {
	{'0', 0}, {'1', 1},
	{'2', 2}, {'3', 3},
	{'4', 4}, {'5', 5},
	{'6', 6}, {'7', 7},
	{'8', 8}, {'9', 9},
	{'A', 10}, {'B', 11},
	{'C', 12}, {'D', 13},
	{'E', 14}, {'F', 15}
  };
  val.MakeUpper();
  TCHAR *mstr = val.GetBuffer(val.GetLength());
  val.ReleaseBuffer();
  TCHAR *s = mstr;
  int result = 0;
  if (*s == '0' && *(s + 1) == 'X') s += 2;
  bool firsttime = true;
  while (*s != '\0')
  {
	bool found = false;
	for (int i = 0; i < HexMapL; i++)
	{
	  if (*s == HexMap[i].chr)
	  {
		if (!firsttime) result <<= 4;
		result |= HexMap[i].value;
		found = true;
		break;
	  }
	}
	if (!found) break;
	s++;
	firsttime = false;
  }
  return result;
}
 
LRESULT CBurnCDDlg::OnBurnFinished(WPARAM hResult, LPARAM lpMessage)
{
	m_BurnButtonClicked = 0;
	if (lpMessage != NULL)
	{
		if (hResult == -3)
		{
			m_nCurrentMode = PROGRAM_IDLE;
			m_progressText.SetWindowText((LPCTSTR)lpMessage);
			m_bufferText.SetWindowTextA(_T("Buffer Empty"));
			MessageBox((LPCTSTR)lpMessage);
		}
		else
		{
			if (SUCCEEDED((HRESULT)hResult))
			{
				if (m_nCurrentMode == AUDIOCD_DISC || m_nCurrentMode == AUDIOCD_DAO)
				{
					m_progressText.SetWindowText(_T("Music CD Successfully Completed"));
					m_bufferText.SetWindowTextA(_T("Buffer Empty"));
					PlayCompletedSound();
					m_nCurrentMode = PROGRAM_IDLE;
					
					if (m_CheckShutdown.GetCheck() == 1)
					{
						ShutDownWindows();
					}
					//else
					//	MessageBox(_T("Music CD Successfully Completed"));
				}
				else
				{
					m_nCurrentMode = PROGRAM_IDLE;
					m_progressText.SetWindowText(_T("Burn Successfully Completed"));
					m_bufferText.SetWindowTextA(_T("Buffer Empty"));
					PlayCompletedSound();
					if (m_CheckShutdown.GetCheck() == 1)
					{
						ShutDownWindows();
					}
					//else
					//	MessageBox(_T("Burn Successfully Completed"));
				}
			}
			else
			{
				CString errorstr;
				GetImapiErrorString((int)hResult, &errorstr);
				m_progressText.SetWindowText(errorstr);
				MessageBox(_T(errorstr));
				m_nCurrentMode = PROGRAM_IDLE;
			}
		}
	}
	else
	{
		if (SUCCEEDED((HRESULT)hResult))
		{
			m_nCurrentMode = PROGRAM_IDLE;
			m_progressText.SetWindowText(_T("Burn completed successfully"));
			PlayCompletedSound();
			if (m_CheckShutdown.GetCheck() == 1)
			{
				ShutDownWindows();
			}
		}
		else
		{
			CString message;
			message.Format(_T("Burn failed! Error: 0x%08x"), hResult);
			m_progressText.SetWindowText(message);
			m_nCurrentMode = PROGRAM_IDLE;
		}
	}
	m_NumberofCopies.SetWindowText("1");
	m_nNumberofCopies = 1;
	EnableUI(TRUE);
	//SaveGraphData();
	return 0;
}

void CBurnCDDlg::GetImapiErrorString(int error, CString *text)
{
	switch (error)
	{	
		case E_IMAPI_REQUEST_CANCELLED:
			text->Format(_T("Burn cancelled"));
		break;
		case E_IMAPI_RECORDER_REQUIRED:
			text->Format(_T("Burner not selected."));
			break;
		case S_IMAPI_WRITE_NOT_IN_PROGRESS:
			text->Format(_T("No current burn operation"));
			break;
		case S_IMAPI_SPEEDADJUSTED:
			text->Format(_T("Requested speed not supported, adjusted"));
		break;
		case S_IMAPI_ROTATIONADJUSTED:
			text->Format(_T("Disc rotation auto adjusted"));
		break;
		case S_IMAPI_BOTHADJUSTED:
			text->Format(_T("Speed and Rotation auto adjusted"));
		break;
		case S_IMAPI_COMMAND_HAS_SENSE_DATA:
			text->Format(_T("Command accepted but error returned"));
		break;
		case E_IMAPI_RAW_IMAGE_IS_READ_ONLY:
			text->Format(_T("Image is now read-only"));
		break;
		case E_IMAPI_RAW_IMAGE_TOO_MANY_TRACKS:
			text->Format(_T("Maximum audio tracks reached"));
		break;
		case E_IMAPI_RAW_IMAGE_NO_TRACKS:
			text->Format(_T("No tracks added"));
		break;
		case E_IMAPI_RAW_IMAGE_SECTOR_TYPE_NOT_SUPPORTED:
			text->Format(_T("Sector type not supported"));
		break;
		case E_IMAPI_RAW_IMAGE_TRACKS_ALREADY_ADDED:
			text->Format(_T("Tracks already added"));
		break;
		case E_IMAPI_RAW_IMAGE_INSUFFICIENT_SPACE:
			text->Format(_T("Not enough space for track"));
		break;
		case E_IMAPI_RAW_IMAGE_TOO_MANY_TRACK_INDEXES:
			text->Format(_T("99 Track limit reached"));
		break;
		case E_IMAPI_RAW_IMAGE_TRACK_INDEX_NOT_FOUND:
			text->Format(_T("LBA offset not valid"));
		break;
		case S_IMAPI_RAW_IMAGE_TRACK_INDEX_ALREADY_EXISTS:
			text->Format(_T("LBA offset already exists"));
		break;
		case E_IMAPI_RAW_IMAGE_TRACK_INDEX_OFFSET_ZERO_CANNOT_BE_CLEARED:
			text->Format(_T("LBA offset zero cannot be cleared"));
		break;
		case E_IMAPI_RAW_IMAGE_TRACK_INDEX_TOO_CLOSE_TO_OTHER_INDEX:
			text->Format(_T("each index not min of 10 sectors"));
		break;
		case E_IMAPI_RECORDER_NO_SUCH_MODE_PAGE:
			text->Format(_T("Requested page mode not supported"));
		break;
		case E_IMAPI_RECORDER_MEDIA_NO_MEDIA:
			text->Format(_T("No disc is loaded in the drive"));
		break;
		case E_IMAPI_RECORDER_MEDIA_INCOMPATIBLE:
			text->Format(_T("Disc is not compatible"));
		break;
		case E_IMAPI_RECORDER_MEDIA_UPSIDE_DOWN:
			text->Format(_T("Disc is upside down in drive"));
		break;
		case E_IMAPI_RECORDER_MEDIA_BECOMING_READY:
			text->Format(_T("Drive not ready"));
		break;
		case E_IMAPI_RECORDER_MEDIA_FORMAT_IN_PROGRESS:
			text->Format(_T("Format in progress"));
		break;
		case E_IMAPI_RECORDER_MEDIA_BUSY:
			text->Format(_T("drive is busy"));
		break;
		case E_IMAPI_RECORDER_INVALID_MODE_PARAMETERS:
			text->Format(_T("Mode page parameters not supported"));
		break;
		case E_IMAPI_RECORDER_MEDIA_WRITE_PROTECTED:
			text->Format(_T("Media is read only"));
		break;
		case E_IMAPI_RECORDER_NO_SUCH_FEATURE:
			text->Format(_T("Requested feature page not supported"));
		break;
		case E_IMAPI_RECORDER_FEATURE_IS_NOT_CURRENT:
			text->Format(_T("Requested feature is not current"));
		break;
		case E_IMAPI_RECORDER_GET_CONFIGURATION_NOT_SUPPORTED:
			text->Format(_T("GET CONFIGURATION not supported"));
		break;
		case E_IMAPI_RECORDER_COMMAND_TIMEOUT:
			text->Format(_T("Timeout occurred"));
		break;
		case E_IMAPI_RECORDER_DVD_STRUCTURE_NOT_PRESENT:
			text->Format(_T("Incompatible drive or disc"));
		break;
		case E_IMAPI_RECORDER_MEDIA_SPEED_MISMATCH:
			text->Format(_T("Disc speeed not compatible"));
		break;
		case E_IMAPI_RECORDER_LOCKED:
			text->Format(_T("Drive is locked"));
		break;
		case E_IMAPI_RECORDER_CLIENT_NAME_IS_NOT_VALID:
			text->Format(_T("Invalid client name"));
		break;
		case E_IMAPI_RECORDER_INVALID_RESPONSE_FROM_DEVICE:
			text->Format(_T("Invalid data"));
		break;
		case E_IMAPI_LOSS_OF_STREAMING:
			text->Format(_T("Data stream lost"));
		break;
		case E_IMAPI_UNEXPECTED_RESPONSE_FROM_DEVICE:
			text->Format(_T("un-recoverable error occurred"));
		break;
		case E_IMAPI_DF2DATA_WRITE_IN_PROGRESS:
			text->Format(_T("burn operation in progress"));
		break;
		case E_IMAPI_DF2DATA_WRITE_NOT_IN_PROGRESS:
			text->Format(_T("NO burn operation in progress"));
		break;
		case E_IMAPI_DF2DATA_INVALID_MEDIA_STATE:
			text->Format(_T("Disc not supported"));
		break;
		case E_IMAPI_DF2DATA_STREAM_NOT_SUPPORTED:
			text->Format(_T("Data stream not supported"));
		break;
		case E_IMAPI_DF2DATA_STREAM_TOO_LARGE_FOR_CURRENT_MEDIA:
			text->Format(_T("Disc too small for data"));
		break;
		case E_IMAPI_DF2DATA_MEDIA_NOT_BLANK:
			text->Format(_T("The disc is not blank"));
		break;
		case E_IMAPI_DF2DATA_MEDIA_IS_NOT_SUPPORTED:
			text->Format(_T("Disc type not supported"));
		break;
		case E_IMAPI_DF2DATA_RECORDER_NOT_SUPPORTED:
			text->Format(_T("Drive does not support disc"));
		break;
		case E_IMAPI_DF2DATA_CLIENT_NAME_IS_NOT_VALID:
			text->Format(_T("Client name is not valid"));
		break;
		case E_IMAPI_DF2TAO_WRITE_IN_PROGRESS:
			text->Format(_T("Burn operation in progress"));
		break;
		case E_IMAPI_DF2TAO_WRITE_NOT_IN_PROGRESS:
			text->Format(_T("No burn operation in progress"));
		break;
		case E_IMAPI_DF2TAO_MEDIA_IS_NOT_PREPARED:
			text->Format(_T("Disc not prepared"));
		break;
		case E_IMAPI_DF2TAO_MEDIA_IS_PREPARED:
			text->Format(_T("Disc not released"));
		break;
		case E_IMAPI_DF2TAO_PROPERTY_FOR_BLANK_MEDIA_ONLY:
			text->Format(_T("Property invalid for written disc"));
		break;
		case E_IMAPI_DF2TAO_TABLE_OF_CONTENTS_EMPTY_DISC:
			text->Format(_T("Disc is empty (no TOC)"));
		break;
		case E_IMAPI_DF2TAO_MEDIA_IS_NOT_BLANK:
		case E_IMAPI_DF2TAO_MEDIA_IS_NOT_SUPPORTED:
		case E_IMAPI_DF2RAW_MEDIA_IS_NOT_SUPPORTED:
			text->Format(_T("Only blank CD-R/RW supported"));
		break;
		case E_IMAPI_DF2TAO_TRACK_LIMIT_REACHED:
			text->Format(_T("99 Track limit reached"));
		break;
		case E_IMAPI_DF2TAO_NOT_ENOUGH_SPACE:
			text->Format(_T("Not enough space"));
		break;
		case E_IMAPI_DF2TAO_NO_RECORDER_SPECIFIED:
			text->Format(_T("No burner chosen"));
		break;
		case E_IMAPI_DF2TAO_INVALID_ISRC:
			text->Format(_T("ISRC invalid"));
		break;
		case E_IMAPI_DF2TAO_INVALID_MCN:
			text->Format(_T("MCN invalid"));
		break;
		case E_IMAPI_DF2TAO_STREAM_NOT_SUPPORTED:
			text->Format(_T("Audio stream invalid"));
		break;
		case E_IMAPI_DF2TAO_RECORDER_NOT_SUPPORTED:
			text->Format(_T("Burner operation not supported"));
		break;
		case E_IMAPI_DF2TAO_CLIENT_NAME_IS_NOT_VALID:
		case E_IMAPI_DF2RAW_CLIENT_NAME_IS_NOT_VALID:
		case E_IMAPI_ERASE_CLIENT_NAME_IS_NOT_VALID:
			text->Format(_T("Client name invalid"));
		break;
		case E_IMAPI_DF2RAW_WRITE_IN_PROGRESS:
			text->Format(_T("Burn operation in progress"));
		break;
		case E_IMAPI_DF2RAW_WRITE_NOT_IN_PROGRESS:
			text->Format(_T("No burn operation progress"));
		break;
		case E_IMAPI_DF2RAW_MEDIA_IS_NOT_PREPARED:
			text->Format(_T("Disc not prepared"));
		break;
		case E_IMAPI_DF2RAW_MEDIA_IS_PREPARED:
			text->Format(_T("Disc not released"));
		break;
		case E_IMAPI_DF2RAW_NOT_ENOUGH_SPACE:
			text->Format(_T("No enough space on disc"));
		break;
		case E_IMAPI_DF2RAW_NO_RECORDER_SPECIFIED:
			text->Format(_T("No burner chosen"));
		break;
		case E_IMAPI_DF2RAW_STREAM_NOT_SUPPORTED:
			text->Format(_T("Data stream invalid"));
		break;
		case E_IMAPI_DF2RAW_DATA_BLOCK_TYPE_NOT_SUPPORTED:
			text->Format(_T("Data block type not supported"));
		break;
		case E_IMAPI_DF2RAW_STREAM_LEADIN_TOO_SHORT:
			text->Format(_T("Lead-in too short"));
		break;
		case E_IMAPI_DF2RAW_RECORDER_NOT_SUPPORTED:
			text->Format(_T("Disc format wrong for operation"));
		break;
		case E_IMAPI_ERASE_RECORDER_IN_USE:
			text->Format(_T("Erase currently in progress"));
		break;
		case E_IMAPI_ERASE_ONLY_ONE_RECORDER_SUPPORTED:
			text->Format(_T("Only one burner supported at once"));
		break;
		case E_IMAPI_ERASE_DISC_INFORMATION_TOO_SMALL:
			text->Format(_T("Erase disc information too small"));
		break;
		case E_IMAPI_ERASE_MODE_PAGE_2A_TOO_SMALL:
			text->Format(_T("Erase mode page 2A too small"));
		break;
		case E_IMAPI_ERASE_MEDIA_IS_NOT_ERASABLE:
			text->Format(_T("Disc is not erasable"));
		break;
		case E_IMAPI_ERASE_DRIVE_FAILED_ERASE_COMMAND:
			text->Format(_T("Erase Failed"));
		break;
		case E_IMAPI_ERASE_TOOK_LONGER_THAN_ONE_HOUR:
			text->Format(_T("Erase took too long"));
		break;
		case E_IMAPI_ERASE_UNEXPECTED_DRIVE_RESPONSE_DURING_ERASE:
			text->Format(_T("Unexpected erase error"));
		break;
		case E_IMAPI_ERASE_DRIVE_FAILED_SPINUP_COMMAND:
			text->Format(_T("Drive spin up failed"));
		break;
		case E_IMAPI_ERASE_MEDIA_IS_NOT_SUPPORTED:
			text->Format(_T("Disc is not supported"));
		break;
		case E_IMAPI_ERASE_RECORDER_NOT_SUPPORTED:
			text->Format(_T("Operation  not supported on this disc"));
		break;
		case  IMAPI_E_FSI_INTERNAL_ERROR:
			text->Format(_T("FSI_INTERNAL_ERROR"));
		break;
		case  IMAPI_E_NO_OUTPUT:
			text->Format(_T("_NO_OUTPUT"));
		break;
		case  IMAPI_E_INVALID_VOLUME_NAME:
			text->Format(_T("INVALID_VOLUME_NAME"));
		break;
		case  IMAPI_E_INVALID_DATE:
			text->Format(_T("INVALID_DATE"));
		break;
		case  IMAPI_E_FILE_SYSTEM_NOT_EMPTY:
			text->Format(_T("_FILE_SYSTEM_NOT_EMPTY"));
		break;
		case  IMAPI_E_FILE_SYSTEM_CHANGE_NOT_ALLOWED:
			text->Format(_T("FILE_SYSTEM_CHANGE_NOT_ALLOWED"));
		break;
		case  IMAPI_E_NOT_FILE:
			text->Format(_T("NOT_FILE"));
		break;
		case  IMAPI_E_NOT_DIR:
			text->Format(_T("NOT_DIR"));
		break;
		case  IMAPI_E_DIR_NOT_EMPTY:
			text->Format(_T("NOT_EMPTY"));
		break;
		case  IMAPI_E_NOT_IN_FILE_SYSTEM:
			text->Format(_T("NOT_IN_FILE_SYSTEM"));
		break;
		case  IMAPI_E_INVALID_PATH:
			text->Format(_T("INVALID_PATH"));
		break;
		case  IMAPI_E_RESTRICTED_NAME_VIOLATION:
			text->Format(_T("RESTRICTED_NAME_VIOLATION"));
		break;
		case  IMAPI_E_DUP_NAME:
			text->Format(_T("DUP_NAME"));
		break;
		case  IMAPI_E_NO_UNIQUE_NAME:
			text->Format(_T("NO_UNIQUE_NAME"));
		break;
		case  IMAPI_E_ITEM_NOT_FOUND:
			text->Format(_T("ITEM_NOT_FOUND"));
		break;
		case  IMAPI_E_FILE_NOT_FOUND:
			text->Format(_T("FILE_NOT_FOUND"));
		break;
		case  IMAPI_E_DIR_NOT_FOUND:
			text->Format(_T("_DIR_NOT_FOUND"));
		break;
		case  IMAPI_E_IMAGE_SIZE_LIMIT:
			text->Format(_T("IMAGE_SIZE_LIMIT"));
		break;
		case  IMAPI_E_IMAGE_TOO_BIG:
			text->Format(_T("IMAGE_TOO_BIG"));
		break;
		case  IMAPI_E_IMAGEMANAGER_IMAGE_NOT_ALIGNED:
			text->Format(_T("IMAGEMANAGER_IMAGE_NOT_ALIGNED"));
		break;
		case  IMAPI_E_IMAGEMANAGER_NO_VALID_VD_FOUND:
			text->Format(_T("IMAGEMANAGER_NO_VALID_VD_FOUND"));
		break;
		case  IMAPI_E_IMAGEMANAGER_NO_IMAGE:
			text->Format(_T("IMAGEMANAGER_NO_IMAGE"));
		break;
		case  IMAPI_E_IMAGEMANAGER_IMAGE_TOO_BIG:
			text->Format(_T("IMAGEMANAGER_IMAGE_TOO_BIG"));
		break;
		case  IMAPI_E_DATA_STREAM_INCONSISTENCY:
			text->Format(_T("DATA_STREAM_INCONSISTENCY"));
		break;
		case  IMAPI_E_DATA_STREAM_READ_FAILURE:
			text->Format(_T("DATA_STREAM_READ_FAILURE"));
		break;
		case  IMAPI_E_DATA_STREAM_CREATE_FAILURE:
			text->Format(_T("DATA_STREAM_CREATE_FAILURE"));
		break;
		case  IMAPI_E_DIRECTORY_READ_FAILURE:
			text->Format(_T("DIRECTORY_READ_FAILURE"));
		break;
		case  IMAPI_E_TOO_MANY_DIRS:
			text->Format(_T("TOO_MANY_DIRS"));
		break;
		case  IMAPI_E_ISO9660_LEVELS:
			text->Format(_T("ISO9660_LEVELS"));
		break;
		case  IMAPI_E_DATA_TOO_BIG:
			text->Format(_T("DATA_TOO_BIG.  Try setting File System to UDF V2.50"));
		break;
		case  IMAPI_E_STASHFILE_OPEN_FAILURE:
			text->Format(_T("STASHFILE_OPEN_FAILURE"));
		break;
		case  IMAPI_E_STASHFILE_SEEK_FAILURE:
			text->Format(_T("STASHFILE_SEEK_FAILURE"));
		break;
		case  IMAPI_E_STASHFILE_WRITE_FAILURE:
			text->Format(_T("STASHFILE_WRITE_FAILURE"));
		break;
		case  IMAPI_E_STASHFILE_READ_FAILURE:
			text->Format(_T("STASHFILE_READ_FAILURE"));
		break;
		case  IMAPI_E_INVALID_WORKING_DIRECTORY:
			text->Format(_T("INVALID_WORKING_DIRECTORY"));
		break;
		case  IMAPI_E_WORKING_DIRECTORY_SPACE:
			text->Format(_T("WORKING_DIRECTORY_SPACE"));
		break;
		case  IMAPI_E_STASHFILE_MOVE:
			text->Format(_T("STASHFILE_MOVE"));
		break;
		case  IMAPI_E_BOOT_IMAGE_DATA:
			text->Format(_T("BOOT_IMAGE_DATA"));
		break;
		case  IMAPI_E_BOOT_OBJECT_CONFLICT:
			text->Format(_T("BOOT_OBJECT_CONFLICT"));
		break;
		case  IMAPI_E_BOOT_EMULATION_IMAGE_SIZE_MISMATCH:
			text->Format(_T("BOOT_EMULATION_IMAGE_SIZE_MISMATCH"));
		break;
		case  IMAPI_E_EMPTY_DISC:
			text->Format(_T("EMPTY_DISC"));
		break;
		case  IMAPI_E_NO_SUPPORTED_FILE_SYSTEM:
			text->Format(_T("NO_SUPPORTED_FILE_SYSTEM"));
		break;
		case  IMAPI_E_FILE_SYSTEM_NOT_FOUND:
			text->Format(_T("FILE_SYSTEM_NOT_FOUND"));
		break;
		case  IMAPI_E_FILE_SYSTEM_READ_CONSISTENCY_ERROR:
			text->Format(_T("READ_CONSISTENCY_ERROR"));
		break;
		case  IMAPI_E_FILE_SYSTEM_FEATURE_NOT_SUPPORTED:
			text->Format(_T("FEATURE_NOT_SUPPORTED"));
		break;
		case  IMAPI_E_IMPORT_TYPE_COLLISION_FILE_EXISTS_AS_DIRECTORY:
			text->Format(_T("COLLISION_FILE_EXISTS_AS_DIRECTORY"));
		break;
		case  IMAPI_E_IMPORT_SEEK_FAILURE:
			text->Format(_T("IMPORT_SEEK_FAILURE"));
		break;
		case  IMAPI_E_IMPORT_READ_FAILURE:
			text->Format(_T("IMPORT_READ_FAILURE"));
		break;
		case  IMAPI_E_DISC_MISMATCH:
			text->Format(_T("DISC_MISMATCH"));
		break;
		case  IMAPI_E_IMPORT_MEDIA_NOT_ALLOWED:
			text->Format(_T("IMPORT_MEDIA_NOT_ALLOWED"));
		break;
		case  IMAPI_E_UDF_NOT_WRITE_COMPATIBLE:
			text->Format(_T("UDF_NOT_WRITE_COMPATIBLE"));
		break;
		case  IMAPI_E_INCOMPATIBLE_MULTISESSION_TYPE:
			text->Format(_T("INCOMPATIBLE_MULTISESSION_TYPE"));
		break;
		case  IMAPI_E_INCOMPATIBLE_PREVIOUS_SESSION:
			text->Format(_T("INCOMPATIBLE_PREVIOUS_SESSION"));
		break;
		case  IMAPI_E_NO_COMPATIBLE_MULTISESSION_TYPE:
			text->Format(_T("NO_COMPATIBLE_MULTISESSION_TYPE"));
		break;
		case  IMAPI_E_MULTISESSION_NOT_SET:
			text->Format(_T("MULTISESSION_NOT_SET"));
		break;
		case  IMAPI_E_IMPORT_TYPE_COLLISION_DIRECTORY_EXISTS_AS_FILE:
			text->Format(_T("COLLISION_DIRECTORY_EXISTS_AS_FILE"));
		break;
		case  IMAPI_E_BAD_MULTISESSION_PARAMETER:
			text->Format(_T("BAD_MULTISESSION_PARAMETER"));
		break;
		case  IMAPI_S_IMAGE_FEATURE_NOT_SUPPORTED:
			text->Format(_T("IMAGE_FEATURE_NOT_SUPPORTED"));
		break;
		default:
			text->Format(_T("Error:Imapi %d"), error);
		break;
	}
}

void __stdcall mycb (unsigned long fcnt, unsigned long bcnt, struct mad_header *mhdr) 
{
	
	/*
	 * If this is the first iteration (frame count is one)
	 * then print out the MP3 layer information. Using this logic
	 * one can retrieve information about the MP3 file, such as 
	 * channels, layer, etc., that might be useful to the calling
	 * code.
	 */	
	if (fcnt == 1) 
	{
		//printf("frame:%d, tot. bytes:%d, layer:%d, mode:%d\n",
		//		fcnt,
		//		bcnt,
		//		mhdr->layer, 
		//		mhdr->mode);
	}
	else 
	{
	//	CString str;
	//	str.Format(_T("Mp3 Conversion frame:%d, bytes:%d"),fcnt, bcnt);
	//	SendMessage(pThis->m_hWnd, WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str.GetBuffer(0));
	}
	
}

int CBurnCDDlg::ConvertMP3toWAV(CString* infile,  CString* outfile)
{
	CString statmsg;
	int  status = CbMpegAudioDecoder(infile->GetBuffer(0), outfile->GetBuffer(0), 1, statmsg.GetBuffer(256), mycb);
	statmsg.ReleaseBuffer();
	return status;
}

void CBurnCDDlg::OnClickedUpdateButton()
{
	CString cVersion;
	if (FileExists("WebUpdate.dll", false) == 0)
	{
		GetFileVersionString(&cVersion);
		WU_Initialize(WEBSITE,  VERFILEFOLDER, VERFILENAME, BINFILEWEBSITE, BINFILEPATH, PROGRAMEXENAME, REGISTRYNAME, PROGRAMDISPLAYNAME, cVersion.GetBuffer(0), "", PROGRAMWITHAUTHOR);
	}	

}

void CBurnCDDlg::DoWizard(BOOL bFromButton)
{
	WizardDlg = new CWizard;
	if (WizardDlg == NULL)
		return;
	if (bFromButton == TRUE)
	{
		WizardDlg->EnableWizardOK = TRUE;
		WizardDlg->m_FromButton = TRUE;
	}
	WizardDlg->DoModal();
	m_WizardMode = WizardDlg->m_WizardMode;
	switch (m_WizardMode)
	{
		case -1:
			return;
		break;
		case WIZARD_BDROM:
			m_FileSystemCombo.SetCurSel(FS_UDF);
			m_UDFRevision.SetCurSel(UDF_250);	
			m_closeMedia.SetCheck(1);
			m_RadioBurnFilesFolders = 0;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the BDMV/CERTIFICATE folders in to the list, select the drive/media and click burn");
		break;
		case WIZARD_DATA:
			m_FileSystemCombo.SetCurSel(FS_ISO9660_JOLIET);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_closeMedia.SetCheck(0);
			m_RadioBurnFilesFolders = 0;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the files/folders in to the list, select the drive/media and click burn");
		break;
		case WIZARD_DVDVIDEO: 
			m_FileSystemCombo.SetCurSel(FS_UDF);
			m_UDFRevision.SetCurSel(UDF_102);	
			m_RadioBurnFilesFolders = 0;
			m_closeMedia.SetCheck(1);
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the VIDEO_TS/AUDIO_TS folders in to the list, select the drive/media and click burn");
		break;
		case WIZARD_ISOWRITE:
			m_closeMedia.SetCheck(BST_CHECKED);
			m_FileSystemCombo.SetCurSel(FS_AUTO);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_closeMedia.SetCheck(1);
			m_RadioBurnFilesFolders = 1;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag a single ISO file in to the list, select the drive/media and click burn");
		break;
		case WIZARD_MAKEISO:
			m_FileSystemCombo.SetCurSel(FS_AUTO);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_deviceComboBox.SetCurSel(m_deviceComboBox.GetCount()-1);
			m_RadioBurnFilesFolders = 0;
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the files/folders in to the list, click burn then choose the filename and path");
		break;
		case WIZARD_MUSICCD: 
		{
			m_FileSystemCombo.SetCurSel(FS_AUDIOCD);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_closeMedia.SetCheck(1);
			m_RadioBurnFilesFolders = 0;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the MP3 and or WAV files in to the list, select the drive/media and click burn");
		}
		break;
		case WIZARD_MUSICCDDAO:
		{
//			DWORD SectorsPerCluster=0;     // sectors per cluster
//			DWORD BytesPerSector=0;        // bytes per sector
//			DWORD NumberOfFreeClusters=0;  // free clusters
//			DWORD TotalNumberOfClusters=0; // total clusters
//			CString drive;
//			GetTempPath( MAX_PATH, drive.GetBuffer(MAX_PATH));
//			GetDiskFreeSpace(drive, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, &TotalNumberOfClusters);
//			float bytes = (float)(SectorsPerCluster * NumberOfFreeClusters)* BytesPerSector;
//			if ((bytes/1024)/1024 < 800)
//				m_FileSystemCombo.SetCurSel(FS_AUDIOCD);
//			else
				m_FileSystemCombo.SetCurSel(FS_AUDIOCD_DAO);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_closeMedia.SetCheck(1);
			m_RadioBurnFilesFolders = 0;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the MP3 and or WAV files in to the list, select the drive/media and click burn");
		}
		break;
		case WIZARD_PHOTOCD:
			m_FileSystemCombo.SetCurSel(FS_ISO9660_JOLIET);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_closeMedia.SetCheck(0);
			m_RadioBurnFilesFolders = 0;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Load or drag the photo files/folders into the list, select the drive/media and click burn");
		break;
		case WIZARD_ERASE:
			m_FileSystemCombo.SetCurSel(FS_AUTO);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_RadioBurnFilesFolders = 0;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Choose the drive with the disc to be erased and click the erase icon button");
		break;
		case WIZARD_ISOFROMDISC:
			m_FileSystemCombo.SetCurSel(FS_AUTO);
			m_UDFRevision.SetCurSel(UDF_AUTO);	
			m_RadioBurnFilesFolders = 1;
			if (m_deviceComboBox.GetCount()-1 == m_deviceComboBox.GetCurSel())
				m_deviceComboBox.SetCurSel(0);
			pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Choose the drive with the disc and click the disc icon button");
		break;
	}
	WizardDlg->m_FromButton = FALSE;
	UpdateData(FALSE);
	delete WizardDlg;
	WizardDlg = NULL;
}

void CBurnCDDlg::OnClickedButtonWizard()
{
	DoWizard(TRUE);
}


void CBurnCDDlg::OnTimer(UINT_PTR nIDEvent)
{
	CString cVersion = "         ";
	switch (nIDEvent)
	{
		case STARTUP_TIMER:
			KillTimer(STARTUP_TIMER);
			AfxBeginThread(AddRecordersToComboBoxThread, this, THREAD_PRIORITY_NORMAL);
			if (GetInt("RunWizardAtStartup", 1))
			{
				DoWizard(FALSE);
			}
			pThis->SetWaitCursor(TRUE);
			OnLbnSelchangeBurnFileList();
			EnableBurnButton();
			SetTimer(UPDATE_TIMER, 5000, NULL);
		break;
		case UPDATE_TIMER:
			KillTimer(UPDATE_TIMER);
			if (FileExists("WebUpdate.dll", false) == 0)
			{
				GetFileVersionString(&cVersion);
				WU_Initialize(WEBSITE,  VERFILEFOLDER, VERFILENAME, BINFILEWEBSITE, BINFILEPATH, PROGRAMEXENAME, REGISTRYNAME, PROGRAMDISPLAYNAME, cVersion.GetBuffer(0), "", PROGRAMWITHAUTHOR, TRUE);
			}	
		break;
	}
	CDialog::OnTimer(nIDEvent);
}

#include "Settings.h"
void CBurnCDDlg::OnMenuToolsSettings()
{
	CSettings dlg;
	dlg.DoModal();
	GetDisplayColors();
	//m_estimatedTime.SetDisplayColors(back, on, off);
	//m_timeLeft.SetDisplayColors(back, on, off);
	SetBackgroundColor();
	Invalidate();
	ShowWindow(SW_HIDE);
	ShowWindow(SW_SHOW);
}

void CBurnCDDlg::SetBackgroundColor()
{
	CDialogEx::SetBackgroundColor(GetInt("BackgroundColor", RGB(230,238,235)), TRUE);
}

void CBurnCDDlg::OnHelpDvdinfoproburnerontheweb()
{
	ShellExecute(this->m_hWnd, "open", "http://www.magicburner.com" , NULL, NULL, SW_SHOWNORMAL);	
}


void CBurnCDDlg::OnHelpAboutdvdinfoproburner()
{
	CAbout dlgAbout;
	dlgAbout.DoModal();
}

void CBurnCDDlg::GetDisplayColors()
{
	int index = GetInt("Colors", 1);
	switch (index)
	{
	case 0:
		back =BACKLITLCDBACKGROUND;
		on   =BLACK;
		off  =BACKLITLCDOFFCOLOR;
		break;
	case 1:
		back =BLACK;
		on   =BLUEONCOLOR;
		off  =BLUEOFFCOLOR;
		break;
	case 2:
		back =BLACK;
		on   =GREENONCOLOR;
		off  =GREENOFFCOLOR;
		break;
	case 3:
		back =LCDBACKGROUND;
		on   =BLACK;
		off  =LCDOFFCOLOR;
		break;
	case 4:
		back =BLACK;
		on   =ORANGEONCOLOR;
		off  =ORANGEOFFCOLOR;
		break;
	case 5:
		back =BLACK;
		on   =PURPLEONCOLOR;
		off  =PURPLEOFFCOLOR;
		break;
	case 6:
		back =BLACK;
		on   =REDONCOLOR;
		off  =REDOFFCOLOR;
		break;
	case 7:
		back =BLACK;
		on   =WHITEONCOLOR;
		off  =WHITEOFFCOLOR;
		break;
	case 8:
		back =BLACK;
		on   =YELLOWONCOLOR;
		off  =YELLOWOFFCOLOR;
		break;
	default:
		back =BLACK;
		on   =BLUEONCOLOR;
		off  =BLUEOFFCOLOR;
		break;
	}
	
}

ULONGLONG CBurnCDDlg::GetDVDLayer0End()
{
	BYTE buffer[2052];
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder == NULL)
		return 0;
	CString dletter = discRecorder->GetVolumePath(0);
	dletter += ":";
	CDevice dev;
	cdb.CurrentDevice = &dev;
	strncpy_s(dev.m_cDriveLetter, 3,  dletter, 3);
	cdb.associate(cdb.CurrentDevice->m_cDriveLetter);
	memset(buffer, 0, 2052);
	cdb[0] = SCSI_Cmd_ReadDvdStruct;
	cdb[8] =  ((2052 >> 8) & 0xff);
	cdb[9] =  (2052 & 0xff);
	cdb[11] = 0;
	int error = cdb.sendcommand(READ, buffer, 2052);
	if (!error)
	{
		ULONG MaxLBALayer0 = (buffer[13+4] << 16) | (buffer[14+4] << 8) | buffer[15+4];
		ULONG iLayers = (buffer[2 + 4] & 0x60) >> 5;
		BOOL bLayerType = (buffer[2+4]&0x10) >> 4;
		ULONG iNumLayers = (buffer[2+4]&0x60) >> 5;
		ULONG iLayerType = buffer[2+4]&0xF;
		if (MaxLBALayer0 == 0)
		{
			MaxLBALayer0 = 2000158;  //For parallel track path DVD-9 = 3.815GB
		}
		if (iLayers > 0)
			return MaxLBALayer0;
	}
	return 0;
}

ULONGLONG CBurnCDDlg::GetLayer0End()
{
	IMAPI_MEDIA_PHYSICAL_TYPE mediaType = pThis->GetCurrentMediaType();
	switch (mediaType)
	{
		case IMAPI_MEDIA_TYPE_DVDPLUSR:
		case IMAPI_MEDIA_TYPE_DVDPLUSRW:
		case IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:
		case IMAPI_MEDIA_TYPE_DVDDASHR:
		case IMAPI_MEDIA_TYPE_DVDDASHRW:
		case IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
		case IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
			return GetDVDLayer0End();
		break;	
		case IMAPI_MEDIA_TYPE_BDR:
		case IMAPI_MEDIA_TYPE_BDRE:
			return GetBDLayer0End();
		break;
		default:
			return 0;
		break;
	}

}

ULONGLONG CBurnCDDlg::GetBDLayer0End()
{
	//Get Performace to get end of layer 0 on BD
	//GET PERFORMANCE command requesting Unusable Data Area (Type = 01h)
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return -1;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder == NULL)
		return 0;
	CString dletter = discRecorder->GetVolumePath(0);
	dletter += ":";
	CDevice dev;
	cdb.CurrentDevice = &dev;
	strncpy_s(dev.m_cDriveLetter, 3,  dletter, 3);
	cdb.associate(cdb.CurrentDevice->m_cDriveLetter);
		
	ULONGLONG ll_endoflayer0 = 0;
	BYTE buf[2048];
	memset(buf, 0, 2048);
	cdb[0]	= SCSI_Cmd_GetPerformance;
	cdb[1]	= 0; //2;
	cdb[2]  = 0x0;
	cdb[3]  = 0x0;
	cdb[4]  = 0x0;
	cdb[5]  = 0x0;
	cdb[9]	= 2;
	cdb[10] = 1;
	cdb[11] = 0;
	int error = cdb.sendcommand(READ, buf, 2048);
	if (error == 0)
		ll_endoflayer0 = buf[0+8] << 24 | buf[1+8] << 16 | buf[2+8] << 8 | buf[3+8]; 
	cdb.CloseAssociateHandle();
	return ll_endoflayer0;
}

LONGLONG CBurnCDDlg::GetBDMaxLBA()
{
	BYTE Buffer[2048];
	memset(Buffer, 0, 2048);
	cdb[0] = SCSI_Cmd_ReadCapacity;
	cdb[9] = 0;
	int error = cdb.sendcommand(READ, Buffer, 8);
	if (error)
		return 0;
	ULONGLONG lba = Buffer[0] << 24 | Buffer[1] << 16 | Buffer[2] << 8 | Buffer[3];
	if (lba > 0)
		return lba;
	else
		return 0;
}

UINT CBurnCDDlg::CreateISOFromDiscThread(LPVOID pParam)
{
	CString filename = pThis->ISOSaveFolder;
	CFile f;
	bool bAudioCD = false;
	int time, Starttime, lapsedsecs, lasttime=0;
	CString msg;
	pThis->GetDlgItem(IDC_BURN_BUTTON)->EnableWindow(TRUE); //enable so we can stop
	pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Initalising please wait...");
	if (f.Open(filename, CFile::modeReadWrite|CFile::modeCreate) == TRUE)
	{
		time = (((COleDateTime::GetCurrentTime().GetHour() * 60) + COleDateTime::GetCurrentTime().GetMinute()) * 60) + COleDateTime::GetCurrentTime().GetSecond();
		Starttime = time;	
		//pThis->m_estimatedTime.SetWindowText("0:00:00");
		//pThis->m_timeLeft.SetWindowText("--:--");

		int CompressedScale = 1, iReadErrors = 0, iLength = 25, bufsize = iLength * 2048, iNumLayers, iLayerType, iLayers = 0;	
		unsigned long  lMaxLBA = 0, lLba = 0, MaxLBALayer0 = 0;
		BOOL bLayerType;
		char str [250];
		BYTE *buffer = new BYTE [bufsize];
		if (buffer == NULL)
		{
			f.Close();
			return 0;
		}
		pThis->m_progressCtrl.SetRange(0, 100);
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Reading source drive please wait...");
		int selectedIndex = pThis->m_deviceComboBox.GetCurSel();
		if (selectedIndex < 0)
			return -1;
		CDiscRecorder* discRecorder = (CDiscRecorder*)pThis->m_deviceComboBox.GetItemDataPtr(selectedIndex);
		if (discRecorder == NULL)
		{
			f.Close();
			return 0;
		}
		CString dletter = discRecorder->GetVolumePath(0);
		dletter += ":";
		CDevice dev;
		pThis->cdb.CurrentDevice = &dev;
		strncpy_s(dev.m_cDriveLetter, 3,  dletter, 3);
		if (pThis->cdb.associate(pThis->cdb.CurrentDevice->m_cDriveLetter) == (int)INVALID_HANDLE_VALUE)
		{
			f.Close();
			return 0;
		}
		int profile = 0;
		pThis->cdb[0]=SCSI_Cmd_GetConfiguration;
		pThis->cdb[7]=0;
		pThis->cdb[8]=8;	//8 bytes only needed
		pThis->cdb[9]=0;
		int error = pThis->cdb.sendcommand(READ, buffer, 8);
		if (!error)
			profile = buffer[6] << 8 | buffer[7];
		if (profile >= 8 && profile <= 0xA)
		{
			iLength = 20;
		}
		else if ((profile >= pDDCDROM && profile <= pDDCDRW) || (profile >= pHDBURNROM && profile <= pHDBURNRW))
			iLength = 20;
		//llTotalBytes = 0;
		memset(buffer, 0, bufsize);
		pThis->cdb[0] = SCSI_Cmd_ReadDvdStruct;
		pThis->cdb[8] =  ((2052 >> 8) & 0xff);
		pThis->cdb[9] =  (2052 & 0xff);
		pThis->cdb[11] = 0;
		error = pThis->cdb.sendcommand(READ, buffer, 2052);//***BUGFIX
		if (!error)
		{
			MaxLBALayer0 = buffer[13+4] << 16 | buffer[14+4] << 8 | buffer[15+4];
			if (MaxLBALayer0 > 0)
				MaxLBALayer0 -= 0x30000;
			iLayers = buffer[2 + 4] & 0x60;
			bLayerType = buffer[2+4]&0x10;
			iNumLayers = buffer[2+4]&0x60;
			iLayerType = buffer[2+4]&0xF;
			if (MaxLBALayer0 == 0)
			{
				MaxLBALayer0 = 2000158;  //For parallel track path DVD-9 = 3.815GB
			}
			if (iLayers > 0)
				CompressedScale = 2;
		}
		memset(buffer, 0, bufsize);
		pThis->cdb[0] = SCSI_Cmd_ReadCapacity;
		pThis->cdb[9] = 0;
		error = pThis->cdb.sendcommand(READ, buffer, 256);
		if (!error)
		{
			lMaxLBA = (buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]);
			if (lMaxLBA == 0)
			{
				delete [] buffer;
				f.Close();
				return 0;
			}
			float size = 0;
			if (profile >= pCDROM && profile <= pCDRW)
			{
				size = (float)lMaxLBA;
				size /= 512;
				sprintf_s(str, 50,  "%4.2fMB", size);
			}
			else if ((profile >= pDDCDROM && profile <= pDDCDRW) || (profile >= pHDBURNROM && profile <= pHDBURNRW))
			{
				size = (float)lMaxLBA;
				size /= 512000;
				sprintf_s(str, 50, "%4.2fGB", size);
			}
			else
			{
				size = (float)lMaxLBA;
				size /= 524288;
				sprintf_s(str, 50, "%4.2fGB", size);
			}
			//m_speedlength.SetWindowText(str);
		}
		else
		{
			delete buffer;
			f.Close();
			return 0;
		}
		float fImageSize = (float)lMaxLBA;
		fImageSize /= 512;  //Convert to MB
		float fDestSize;
		char path[MAX_PATH];
		char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
		_splitpath_s(filename, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT );
		_makepath_s(path, MAX_PATH, drive, dir, NULL, NULL);
		
		LONGLONG i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
		DWORD dwSectPerClust, dwBytesPerSect,  dwFreeClusters, dwTotalClusters;
		if (GetProcAddress( GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA"))
		{
			BOOL fResult = GetDiskFreeSpaceEx(drive, (PULARGE_INTEGER)&i64FreeBytesToCaller, (PULARGE_INTEGER)&i64TotalBytes, (PULARGE_INTEGER)&i64FreeBytes);
			fDestSize = (float) (i64FreeBytesToCaller / 1048576);
		}
		else 
		{
			BOOL fResult = GetDiskFreeSpace (path, &dwSectPerClust, &dwBytesPerSect,  &dwFreeClusters, &dwTotalClusters);
			fDestSize = (float) (((dwFreeClusters * dwSectPerClust) * dwBytesPerSect) / 1048576);
		}
		if ( fDestSize <= fImageSize)
		{
			pThis->cdb.CloseAssociateHandle();
			delete [] buffer;
			f.Close();
			//ShowErrorString("Not enough free space on destination");
			return 0;
		}
		unsigned char *sense=pThis->cdb.sense();
		do
		{	
			pThis->cdb[0] = SCSI_Cmd_TestUnitReady;	// TEST UNIT READY
			pThis->cdb[5] = 0;
			error = pThis->cdb.sendcommand(READ, NULL, 0);
		}while(error);
		memset(buffer, 0, bufsize);
		pThis->cdb[0] = SCSI_Cmd_Read10;
		pThis->cdb[1] = 8;
		pThis->cdb[7] = (iLength&0xFF00) >> 8; 
		pThis->cdb[8] = (iLength&0xFF); 
		pThis->cdb[9] = 0;
		error = pThis->cdb.sendcommand(READ, buffer, bufsize);
		if (error)
		{
			pThis->cdb[0] = SCSI_Cmd_ReadAudioCd;
			pThis->cdb[6] = ((iLength/2)&0xFF0000) >> 16;
			pThis->cdb[7] = ((iLength/2)&0xFF00) >> 8; 
			pThis->cdb[8] = ((iLength/2)&0xFF); 
			pThis->cdb[9] = 0xF8;
			pThis->cdb[11] = 0;
			error = pThis->cdb.sendcommand(READ, buffer, bufsize);
			if (!error)
			{
				delete buffer;
				bufsize = iLength * 2352;
				buffer = new BYTE [bufsize];
				bAudioCD = true;
				//Audio CD	
			}
			if (error)
			{
				//Mo readable media
				delete [] buffer;
				pThis->cdb.CloseAssociateHandle();
				f.Close();
				return 0;
			}
		}
		//PreventAllowMediumRemoval(1);
		pThis->cdb[0] = SCSI_Cmd_PreventAllow;
		pThis->cdb[4] = 1; //prevent		
		pThis->cdb[5] = 0;
		pThis->cdb.sendcommand(READ, NULL, 0);
		
		pThis->cdb[0] = SCSI_Cmd_SetSpeed;
		pThis->cdb[2] = 0xFF;
		pThis->cdb[3] = 0xFF; 
		pThis->cdb[4] = 0xFF; 
		pThis->cdb[5] = 0xFF;
		pThis->cdb[11] = 0;
		pThis->cdb.sendcommand(READ, NULL, 0);
		BYTE command;
		if (bAudioCD == false)
			command = SCSI_Cmd_Read10;
		else
			command = SCSI_Cmd_ReadAudioCd;
		long BlockLBA;
		pThis->m_cancelISOFromDisc = false;
		int loop, lastpercent=0;
//////////////////////////////////////////////////////////
//      Main Loop Start
/////////////////////////////////////////////////////////
		for (; lLba <= lMaxLBA; /*lLba += iLength*/)
		{
			sprintf_s(str, 50, "%Xh", lLba);
			//pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str);
//////////////////////////////////////////////////////////
// Check if stop has been received
/////////////////////////////////////////////////////////
			if (pThis->m_cancelISOFromDisc == TRUE)
			{	
				pThis->cdb[0] = SCSI_Cmd_PreventAllow;
				pThis->cdb[4] = 0; //enable		
				pThis->cdb[5] = 0;
				pThis->cdb.sendcommand(READ, NULL, 0);
				delete buffer;
				f.Close();
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"ISO Write cancelled");
				msg = "ISO Write cancelled";
				goto out;
			}
			error = loop = 0;
			BlockLBA = lLba;
			if (profile >= pCDROM && profile <= pCDRW)
				loop = 4;
			else if ((profile >= pDDCDROM && profile <= pDDCDRW) || (profile >= pHDBURNROM && profile <= pHDBURNRW))
				loop = 8;
			else
				loop = 16*CompressedScale;
			for (int i = 0; i < loop; i++)
			{
				//////////////////////////////////////
				//deal with the last group of blocks
				//////////////////////////////////////
				if (lLba + iLength > lMaxLBA)
				{
					iLength = (lMaxLBA - lLba + 1);
					i = loop;
				}
				if (iLength <= 0)
					break;
				pThis->cdb[0] = command;
				pThis->cdb[2] = (UCHAR)((lLba&0xFF000000) >> 24); 
				pThis->cdb[3] = (UCHAR)((lLba&0x00FF0000) >> 16); 
				pThis->cdb[4] = (UCHAR)((lLba&0x0000FF00) >> 8); 
				pThis->cdb[5] = (UCHAR)((lLba&0x000000FF)); 
				pThis->cdb[7] = (UCHAR)((iLength&0xFF00) >> 8); 
				pThis->cdb[8] = (UCHAR)((iLength&0x00FF)); 
				if (bAudioCD == true)
				{
					pThis->cdb[9] = 0xF8;
					pThis->cdb[11] = 0;
				}
				else
					pThis->cdb[9] = 0;
				error += pThis->cdb.sendcommand(READ, buffer, bufsize);
				lLba += iLength;
				f.Write(buffer, iLength * 2048);	
			}
			if (error)	
			{
				unsigned char *sense=pThis->cdb.sense();
				int s = sense[2]&0x0F;
				int a = sense[12];
				int q =	sense[13];
				if (s == 5 && a == 111 && q == 3)
				{
					/////////////////////////////
					//Fatal error encrypted data
					//////////////////////////////
					pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Read Error");
					delete [] buffer;
					pThis->cdb[0] = SCSI_Cmd_PreventAllow;
					pThis->cdb[4] = 0; //enable		
					pThis->cdb[5] = 0;
					pThis->cdb.sendcommand(READ, NULL, 0);
					f.Close();
					return 0;				
				}	
				bool errfound = false;  
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Disc is encrypted, trying playing in a player first then try again.");
				delete [] buffer;
				pThis->cdb[0] = SCSI_Cmd_PreventAllow;
				pThis->cdb[4] = 0; //enable		
				pThis->cdb[5] = 0;
				pThis->cdb.sendcommand(READ, NULL, 0);
				f.Close();
				return 0;	
			}
			int percent = lLba / (lMaxLBA / 100);
			int hours, mins, secs;	
			pThis->m_progressCtrl.SetPos(percent);
			if ( pThis->m_pTaskbarList )
				pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, percent, 100);
			time = (((COleDateTime::GetCurrentTime().GetHour() * 60) + COleDateTime::GetCurrentTime().GetMinute()) * 60) + COleDateTime::GetCurrentTime().GetSecond();
			lapsedsecs = (time - Starttime);
			CString strText;
			if (lapsedsecs != lasttime)
			{
				lasttime = lapsedsecs;
				hours = lapsedsecs / 3600;
				mins =  (lapsedsecs % 3600) / 60;
				secs =  (lapsedsecs % 3600) % 60;
				strText.Format(_T("%01d:%02d:%02d"), hours, mins, secs);
				//pThis->m_estimatedTime.SetWindowText(strText);
			}
			if (/*percent % 2 &&*/ percent != lastpercent)
			{
				lastpercent = percent;
				int timeleft = (int) ((100.0 / (float)percent) * lapsedsecs);
				timeleft -= lapsedsecs;
				hours = timeleft / 3600;
				mins =  (timeleft % 3600) / 60;
				secs =  (timeleft % 3600) % 60;
				strText.Format(_T("%01d:%02d:%02d"),hours, mins, secs);
				//pThis->m_timeLeft.SetWindowText(strText);
			}
			if (profile >= pCDROM && profile <= pCDRW)
			{
				float rem = (float)lMaxLBA;
				rem -= lLba;
				rem /= 512;
				float done = (float)lLba;
				done /= 512;
				sprintf_s(str, 250,  "Saving ISO Image - Progress: %d%% - %4.2fMB Done %4.2fMB Remaining", percent, done, rem);
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str);
			}
			else
			{
				float rem = (float)lMaxLBA;
				rem -= lLba;
				rem /= 524288;
				float done = (float)lLba;
				done /= 524288;
				sprintf_s(str, 250,  "Saving ISO Image - Progress: %d%% - %4.2fGB Done %4.2fGB Remaining", percent, done, rem);
				pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str);
			}		
		}
		delete [] buffer;
		pThis->m_progressCtrl.SetPos(100);
		if ( pThis->m_pTaskbarList )
			pThis->m_pTaskbarList->SetProgressValue ( pThis->m_hWnd, 100, 100);
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"ISO Create complete");
		pThis->cdb[0] = SCSI_Cmd_PreventAllow;
		pThis->cdb[4] = 0; //enable		
		pThis->cdb[5] = 0;
		pThis->cdb.sendcommand(READ, NULL, 0);		
	}
	else
	{
		pThis->SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)"Error creating ISO file");
		return 0;
	}
	f.Close();
	msg.Format("ISO file %s created successfully", filename);
out:	
	pThis->cdb.CloseAssociateHandle();
	pThis->MessageBox(msg, "Create ISO from Disc", MB_ICONINFORMATION|MB_OK);
	pThis->cdb.CloseAssociateHandle();
	if (pThis->m_ejectWhenFinished.GetCheck())
		pThis->EjectDrive();
	pThis->m_nCurrentMode = PROGRAM_IDLE;
	pThis->EnableUI(TRUE);
	return 0;
}

void CBurnCDDlg::DoNextCopy()
{
	if (m_nNumberofCopies)
	{
		if (m_nCurrentMode == PROGRAM_IDLE)
		{
			m_bWaitingForDisc = false;
			return;
		}
		m_nNumberofCopies--;
		CString str;
		str.Format("Please load the next blank disc.  Remaining %d",  m_nNumberofCopies);
		SendMessage(WM_BURN_STATUS_MESSAGE, 0, (LPARAM)str.GetBuffer(0));
		//EjectDrive();
		//Now wait for a media arrival message
		//set m_bWaitingForDisc to TRUE so
		//the message loop knows another copy
		//is pending.
		//MessageBox("Please put the next blank disc in the drive");
		m_bWaitingForDisc = true;
	}
}

void CBurnCDDlg::StartNextCopy()
{
	//if we are here a new disc arrived and the drive has not changed.
	// as long as m_bWaitingForDisc is still true.
	if (m_bWaitingForDisc)
	{
		if (isMediaLoaded())
		{
			if (isMediaBlank())
			{
				m_bWaitingForDisc = false;
				m_nCurrentMode = PROGRAM_IDLE;  //this needed to prevent burn button cancelling next burn
				OnBnClickedBurnButton();
			}
			else
			{
				EjectDrive();
				MessageBox("Disc is not blank, replace with a blank disc");
			}
		}
		//else keep waiting for a disc to appear here.
	}
}

void CBurnCDDlg::OnChangeEditCopies()
{
	UpdateData(TRUE);
	CString num;
	m_NumberofCopies.GetWindowTextA(num.GetBuffer(10), 10);
	num.ReleaseBuffer();
	int nNum = atoi(num);
	if ( nNum <= 0)
	{
		m_NumberofCopies.SetWindowText("1");
		m_nNumberofCopies = 1;
		UpdateData(FALSE);
		return;
	}
	m_nNumberofCopies = nNum;
}


void CBurnCDDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	if( pScrollBar->GetDlgCtrlID() == IDC_SPIN2 )
	{
		CString str;
		str.Format("%d",nPos);
		m_NumberofCopies.SetWindowText(str);
		m_nNumberofCopies = nPos;
		
	}
	else
		CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CBurnCDDlg::RemoveTrayIcon()
{
	//put icon in the system tray
	NOTIFYICONDATA nid;
	nid.cbSize = sizeof(NOTIFYICONDATA);
	nid.hWnd = m_hWnd;
	nid.uID = ID_SYSTEMTRAY;
	nid.uFlags = 0;
	::Shell_NotifyIcon(NIM_DELETE, &nid);
}

void CBurnCDDlg::AddSystemTrayIcon()
{
	//put icon in the system tray
	SAFE_LOG(out, "AddSystemTrayIcon - Start", true);
	NOTIFYICONDATA nid;
	nid.cbSize = sizeof(NOTIFYICONDATA);
	nid.hWnd = GetSafeHwnd();
	nid.uID = ID_SYSTEMTRAY;
	nid.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
	nid.uCallbackMessage = WM_SYSTEMTRAY;
	nid.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
	_tcscpy_s(nid.szTip, sizeof(nid.szTip), PROGRAMNAME);
	::Shell_NotifyIcon(NIM_ADD, &nid);
	SAFE_LOG(out, "AddSystemTrayIcon - End", true);
}

void CBurnCDDlg::DeleteStatusAreaBalloon()
{
	NOTIFYICONDATA nid;
	nid.cbSize = sizeof(NOTIFYICONDATA);
	nid.hWnd = GetSafeHwnd();
	nid.uFlags = NIF_INFO|NIF_MESSAGE;
	nid.dwInfoFlags = NIIF_INFO;
	nid.uID = ID_SYSTEMTRAY;
	nid.uTimeout = 10000;
	lstrcpyn(nid.szInfo, TEXT( ""), (sizeof(nid.szInfo)/sizeof(nid.szInfo[0])));
	lstrcpyn(nid.szInfoTitle, TEXT(""), (sizeof(nid.szInfo)/sizeof(nid.szInfo[0])));
	nid.uCallbackMessage = WM_TRAY;
	Shell_NotifyIcon(NIM_DELETE, &nid);
}

void CBurnCDDlg::ShowStatusAreaBalloon(char *string)
{
	NOTIFYICONDATA nid;
	nid.cbSize = sizeof(NOTIFYICONDATA);
	nid.hWnd = GetSafeHwnd();
	nid.uFlags = NIF_INFO|NIF_MESSAGE;
	nid.dwInfoFlags = NIIF_INFO;
	nid.uID = ID_SYSTEMTRAY;
	nid.uTimeout = 10000;
	lstrcpyn(nid.szInfo, string, (sizeof(nid.szInfo)/sizeof(nid.szInfo[0])));
	lstrcpyn(nid.szInfoTitle, PROGRAMNAME, (sizeof(nid.szInfo)/sizeof(nid.szInfo[0])));
	nid.uCallbackMessage = WM_TRAY;
	Shell_NotifyIcon(NIM_MODIFY, &nid);
}

LRESULT CBurnCDDlg::OnSystemTray(WPARAM wParam, LPARAM lParam)
{
	//wParam = the nid.uID defined above
	//(useful if you have more than one icon in the tray)
	//lParam = mouse message
	if (wParam == ID_SYSTEMTRAY)
	{
		switch(lParam)
		{
			case WM_LBUTTONDOWN:
					if (IsIconic() )
						ShowWindow(SW_RESTORE);
					else
						ShowWindow(SW_SHOW);
					SetForegroundWindow();
			break;
			case WM_RBUTTONDOWN:
				CMenu menu;
				if (menu.LoadMenu(IDR_MENU1))
				{
					if (IsIconic() )
						ShowWindow(SW_RESTORE);
					else
						ShowWindow(SW_SHOW);
					SetForegroundWindow();
					//Display & track the popup menu
					CPoint point;
					GetCursorPos(&point);
					CMenu menu;
					if (menu.LoadMenu(IDR_MENU1))
					{
						CMenu* pPopup = menu.GetSubMenu(0);
						ASSERT(pPopup != NULL);
						pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
						menu.DestroyMenu();
					}
				}
			break;
		}
	}
	return 1;
}

LRESULT CBurnCDDlg::OnTray(WPARAM wParam, LPARAM lParam)
{
	if (lParam == WM_LBUTTONDOWN)
	{	
		if (IsIconic() )
			ShowWindow(SW_RESTORE);
		else
			ShowWindow(SW_SHOW);
		SetForegroundWindow();
	}
	else if (lParam == WM_RBUTTONUP)
	{
		SetForegroundWindow();
		//Display & track the popup menu
		CPoint point;
		GetCursorPos(&point);
		CMenu menu;
		if (menu.LoadMenu(IDR_MENU1))
		{
			CMenu *pPopup = menu.GetSubMenu(0);
			ASSERT(pPopup != NULL);
			pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this);
			menu.DestroyMenu();
		}
	}
	return 0;
}

void CBurnCDDlg::OnClickedCheckUsecav()
{
	UpdateData(TRUE);
}

/*********************************************************************
FUNCTION: GetSecondsElapsed
		  
PURPOSE: 
SYSTEMTIME startTime;
SYSTEMTIME endTime;
SYSTEMTIME elapsedTime;
GetSystemTime(&startTime);    
GetSystemTime(&endTime);       // gets current time
CalcElapsedTime(&startTime, &endTime, &elapsedTime);
	
*********************************************************************/
 DWORD CBurnCDDlg::GetSecondsElapsed(SYSTEMTIME * StartTime, SYSTEMTIME * EndTime)
 {
	FILETIME Start,End;
	unsigned __int64 Start64=0, End64=0, Elapsed64=0; 
	//--- Convert System time
	SystemTimeToFileTime(StartTime,&Start);
	SystemTimeToFileTime(EndTime,&End);
	//---- Convert start and end file 
	//---- time to 2  64 bit usigned integers
	((LPDWORD)(&Start64))[1] = Start.dwHighDateTime;
	((LPDWORD)(&Start64))[0] = Start.dwLowDateTime;
	((LPDWORD)(&End64))[1] = End.dwHighDateTime;
	((LPDWORD)(&End64))[0] = End.dwLowDateTime;
	//--- Calc elpased time
	Elapsed64 = End64 - Start64;
	//---- Get micro seconds elpased
	Elapsed64 /= 10;
	//--- Get milly seconds elpased
	Elapsed64 /= 1000;
	//--- Get Secconds elpased
	Elapsed64 /= 1000;
	//--- Return the LowDateTime of seconds elapsed
	//--- This will be good enough for ~136 years elapsed
	return(((LPDWORD)(&Elapsed64))[0]);
 }

/*********************************************************************
FUNCTION:CalcElapsedTime
		  
PURPOSE: 
*********************************************************************/
#define SECONDS_IN_A_DAY     ((DWORD)(SECONDS_IN_A_HOUR*24))
#define SECONDS_IN_A_HOUR    ((DWORD)(SECONDS_IN_A_MINUTE*60))
#define SECONDS_IN_A_MINUTE  ((DWORD)(60))
void CBurnCDDlg::CalcElapsedTime(SYSTEMTIME * StartTime, SYSTEMTIME * FinishTime, SYSTEMTIME * ElapsedTime)
{
	DWORD SecondsElapsed;
	memset(ElapsedTime,0,sizeof(SYSTEMTIME));
	SecondsElapsed = GetSecondsElapsed(StartTime, FinishTime);
	if(SecondsElapsed >= SECONDS_IN_A_DAY)
	{
		ElapsedTime->wDay = (WORD) (SecondsElapsed / SECONDS_IN_A_DAY);
		SecondsElapsed -= (ElapsedTime->wDay*SECONDS_IN_A_DAY);
	}
	if(SecondsElapsed >= SECONDS_IN_A_HOUR)
	{
		ElapsedTime->wHour  = (WORD) (SecondsElapsed / SECONDS_IN_A_HOUR);
		SecondsElapsed -= (ElapsedTime->wHour * SECONDS_IN_A_HOUR);
	}
	if(SecondsElapsed >= SECONDS_IN_A_MINUTE)
	{
		ElapsedTime->wMinute = (WORD) (SecondsElapsed / SECONDS_IN_A_MINUTE);
		SecondsElapsed -= (ElapsedTime->wMinute * SECONDS_IN_A_MINUTE);
	}
	ElapsedTime->wSecond = (WORD) SecondsElapsed;
}

void CBurnCDDlg::GetMediaMidCode(CString *midcode)
{
	int selectedIndex = m_deviceComboBox.GetCurSel();
	if (selectedIndex < 0)
		return;
	CDiscRecorder* discRecorder = (CDiscRecorder*)m_deviceComboBox.GetItemDataPtr(selectedIndex);
	if (discRecorder == NULL)
	{
		midcode->Empty();
		return;
	}
	IMAPI_MEDIA_PHYSICAL_TYPE type = GetCurrentMediaType();
	IDiscRecorder2Ex* pDiscRecorder2Ex =  discRecorder->GetIDiscRecorder2ExPtr();
	BYTE *data;
	ULONG_IMAPI2_DVD_STRUCTURE count;
	int i = 0;
	HRESULT hr;
	int index = 0;
	switch (type)
	{
		case IMAPI_MEDIA_TYPE_CDROM:
		case IMAPI_MEDIA_TYPE_CDR:
		case IMAPI_MEDIA_TYPE_CDRW:
		case 	IMAPI_MEDIA_TYPE_DVDROM:
		case 	IMAPI_MEDIA_TYPE_DVDRAM:
		case 	IMAPI_MEDIA_TYPE_DISK:
		case 	IMAPI_MEDIA_TYPE_HDDVDROM:
		case 	IMAPI_MEDIA_TYPE_HDDVDR:
		case 	IMAPI_MEDIA_TYPE_HDDVDRAM:
		case 	IMAPI_MEDIA_TYPE_BDROM:
			midcode->Empty();
		break;
		case 	IMAPI_MEDIA_TYPE_DVDPLUSR:
		case 	IMAPI_MEDIA_TYPE_DVDPLUSRW:
		case 	IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER:
		case 	IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER:
			//format = CDB[7],  address = CDB[2] - CDB[5], layer CDB[6],  agid CDB[10] Bits 6&7
			hr = pDiscRecorder2Ex->ReadDvdStructure( 0, 0, 0, 0, &data, &count);
			if (FAILED(hr))
			{
				hr = pDiscRecorder2Ex->ReadDvdStructure( 0x11, 0, 0, 0, &data, &count);
			}
			if (SUCCEEDED(hr))
			{
				char pname[10], ver[5];
				memset(pname, 0, 10);				
				memset(ver, 0, 5);
				strncpy_s(pname, 10, (const char *)&data[23-4], 8);
				strncpy_s(ver, 5, (const char *)&data[31-4], 3);
				i = 23-4;
				for (; i< 34; i++)
				{
					if (data[i] != 1)
						break;
				}
				if (i >= 33)
				{
					strcpy_s(pname, 10,  "        ");
					strcpy_s(ver, 5, "   ");
				}
				midcode->Format("%-8s%3s",  pname, ver);
			}
			if (FAILED(hr))
				return;
			CoTaskMemFree(data);
		break;
		case 	IMAPI_MEDIA_TYPE_DVDDASHR:
		case 	IMAPI_MEDIA_TYPE_DVDDASHRW:
		case 	IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER:
			hr = pDiscRecorder2Ex->ReadDvdStructure(0x0E, 0, 0, 0, &data, &count);
			if (SUCCEEDED(hr))
			{
				char name[15];
				memset(name, 0 , 15);
				for (int i = 0; i < 14; i++)
				{
					if (i == 6)
						i = 8;
					int ch = data[(21-4)+i];
					if (ch >= 0x20 && ch < 0x7e)
						name[index++] = ch;
				}
				name[index] = 0;
				*midcode = name;
				CoTaskMemFree(data);
			}
		break;
		case 	IMAPI_MEDIA_TYPE_BDR:
		case 	IMAPI_MEDIA_TYPE_BDRE:
			BYTE Cdb[12];
			memset(Cdb, 0, 12);
			char bdname[10], ch;
			memset(bdname,0, 10);
			BYTE sense[18];
			BYTE Buffer[4100];
			ULONG BufferFetched;
			memset(Buffer, 0 , 4100);
			Cdb[0] = 0xAD; //SCSI_Cmd_ReadDvdStruct
			Cdb[1] = 1;
			Cdb[7] = 0;
			Cdb[8] = 4100>>8;
			Cdb[9] = 4100&0x00FF;
			Cdb[11] = 0;
			hr = pDiscRecorder2Ex->SendCommandGetDataFromDevice (Cdb, 12, sense, 10, Buffer, 4100, &BufferFetched);
			//Command for BD is same as for DVD except CBD[1] == 1 rather than 0;
			//format = CDB[7],  address = CDB[2] - CDB[5], layer CDB[6],  agid CDB[10] Bits 6&7
			if (SUCCEEDED(hr))
			{
				//fetch manufacturer ID 6 bytes
				int bdi;
				for (bdi = 0; bdi < 9; bdi++)
				{
					ch = Buffer[4+100+bdi];
					if (ch == 0)
						ch = ' ';
					bdname[bdi] = ch;
				}
				bdname[9] = 0;
				*midcode = bdname;
				//CoTaskMemFree(data);
			}		
		break;
	}
}

void CBurnCDDlg::OnChangeVolume()
{
	UpdateData(TRUE);
	m_volumelabelchanged = TRUE;
}
